From 60ca991c58b2ca93c439516bc4f123709ed269cb Mon Sep 17 00:00:00 2001 From: dpen2000 Date: Sat, 22 Mar 2014 01:32:45 +0000 Subject: [PATCH 01/30] Fix #390 The issue here was configSchema is an attribute within attributes and so revertAttributes and attributes get the same instance of it when clone is used. Later calls to _.equals fail when only configSchema has changed. --- app/models/CocoModel.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index 834dbe061..9bc8ae587 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -86,7 +86,7 @@ class CocoModel extends Backbone.Model res markToRevert: -> - @_revertAttributes = _.clone @attributes + @_revertAttributes = _.cloneDeep @attributes revert: -> @set(@_revertAttributes, {silent: true}) if @_revertAttributes From 6c151acaa782ee7ac62a12d1ebb3ebccf50c6b68 Mon Sep 17 00:00:00 2001 From: dpen2000 Date: Sat, 22 Mar 2014 02:21:23 +0000 Subject: [PATCH 02/30] Optimizations of markToRevert: Switch to using $.extend instead of _.cloneDeep and only when type is not a "ThangType" --- app/models/CocoModel.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index 9bc8ae587..59e9af816 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -86,7 +86,8 @@ class CocoModel extends Backbone.Model res markToRevert: -> - @_revertAttributes = _.cloneDeep @attributes + if @type() != 'ThangType' + @_revertAttributes = $.extend(true, {}, @attributes) revert: -> @set(@_revertAttributes, {silent: true}) if @_revertAttributes From 6b660dade2736f7e8c78f9c87cf6ff2dc76e910d Mon Sep 17 00:00:00 2001 From: 3rr3s3v3n Date: Sat, 22 Mar 2014 10:38:32 +0100 Subject: [PATCH 03/30] Translating Multiplayer lines Ok, I tried to translate in italian some lines ;) hope this helps. --- app/locale/it.coffee | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/locale/it.coffee b/app/locale/it.coffee index 5d2c14f17..b639bf160 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -523,19 +523,19 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # 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" -# 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" -# 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." +# rank_submitting: "Inviando..." +# rank_submitted: "Inviato per essere Valutato" +# rank_failed: "Impossibile Valutare" +# rank_being_ranked: "Il Gioco è stato Valutato" +# code_being_simulated: "Il tuo nuovo codice sarà simulato da altri giocatori per essere valutato. Sarà aggiornato ad ogni nuova partita." +# no_ranked_matches_pre: "Nessuna partita valutata per " +# no_ranked_matches_post: " squadra! Gioca contro altri avversari e poi torna qui affinchè la tua partita venga valutata." +# choose_opponent: "Scegli un avversario" +# tutorial_play: "Gioca il Tutorial" +# tutorial_recommended: "Consigliato se questa è la tua primissima partita" +# tutorial_skip: "Salta il Tutorial" +# tutorial_not_sure: "Non sei sicuro di quello che sta accadendo?" +# tutorial_play_first: "Prima di tutto gioca al Tutorial." # simple_ai: "Simple AI" # warmup: "Warmup" # vs: "VS" From 9e535e19c6d86ce1e754c8bdf8a9500e5fad488a Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sat, 22 Mar 2014 09:05:53 -0700 Subject: [PATCH 04/30] Added resimulateAllSessions route --- server/queues/scoring.coffee | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index f4fc91a91..982cf4124 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -54,6 +54,29 @@ addPairwiseTaskToQueue = (taskPair, cb) -> sendEachTaskPairToTheQueue taskPairs, (taskPairError) -> if taskPairError? then return cb taskPairError,false cb null, true + +module.exports.resimulateAllSessions = (req, res) -> + unless isUserAdmin req then return errors.unauthorized res, "Unauthorized. Even if you are authorized, you shouldn't do this" + + originalLevelID = req.body.originalLevelID + levelMajorVersion = parseInt(req.body.levelMajorVersion) + + findParameters = + submitted: true + level: + original: originalLevelID + majorVersion: levelMajorVersion + + query = LevelSession + .find(findParameters) + .lean() + + query.exec (err, result) -> + if err? then return errors.serverError res, err + result = _.sample result, 10 + async.each result, resimulateSession.bind(@,originalLevelID,levelMajorVersion), (err) -> + if err? then return errors.serverError res, err + sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"} module.exports.createNewTask = (req, res) -> From 51418737253490dda8053828ac1bd1f4fc4de898 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sat, 22 Mar 2014 09:07:01 -0700 Subject: [PATCH 05/30] Added resimulateAllSessions method --- app/views/play/ladder_view.coffee | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/views/play/ladder_view.coffee b/app/views/play/ladder_view.coffee index 653f1961d..9341f97f7 100644 --- a/app/views/play/ladder_view.coffee +++ b/app/views/play/ladder_view.coffee @@ -122,6 +122,19 @@ module.exports = class LadderView extends RootView onClickPlayButton: (e) -> @showPlayModal($(e.target).closest('.play-button').data('team')) + + resimulateAllSessions: -> + postData = + originalLevelID: @level.get('original') + levelMajorVersion: @level.get('version').major + console.log postData + + $.ajax + url: '/queue/scoring/resimulateAllSessions' + method: 'POST' + data: postData + complete: (jqxhr) -> + console.log jqxhr.responseText showPlayModal: (teamID) -> return @showApologeticSignupModal() if me.get('anonymous') From 13a74ba56027b73acadd9758db4830c905f05bfa Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sat, 22 Mar 2014 09:17:14 -0700 Subject: [PATCH 06/30] Added resimulateAllSessions route --- server/routes/queue.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/routes/queue.coffee b/server/routes/queue.coffee index 10af6875f..18d8cc80b 100644 --- a/server/routes/queue.coffee +++ b/server/routes/queue.coffee @@ -14,6 +14,10 @@ module.exports.setup = (app) -> handler = loadQueueHandler 'scoring' handler.messagesInQueueCount req, res + app.post '/queue/scoring/resimulateAllSessions', (req, res) -> + handler = loadQueueHandler 'scoring' + handler.resimulateAllSessions req, res + app.all '/queue/*', (req, res) -> setResponseHeaderToJSONContentType res From d0232a36d9c3848eab5d7a32cfc1e528cc66a309 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sat, 22 Mar 2014 09:19:21 -0700 Subject: [PATCH 07/30] Added resimulateSession method --- server/queues/scoring.coffee | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index 982cf4124..fac34b59f 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -77,6 +77,27 @@ module.exports.resimulateAllSessions = (req, res) -> async.each result, resimulateSession.bind(@,originalLevelID,levelMajorVersion), (err) -> if err? then return errors.serverError res, err sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"} + +resimulateSession = (originalLevelID, levelMajorVersion, session, cb) => + sessionUpdateObject = + submitted: true + submitDate: new Date() + meanStrength: 25 + standardDeviation: 25/3 + totalScore: 10 + numberOfWinsAndTies: 0 + numberOfLosses: 0 + isRanking: true + LevelSession.update {_id: session._id}, sessionUpdateObject, (err, updatedSession) -> + if err? then return cb err, null + opposingTeam = calculateOpposingTeam(session.team) + fetchInitialSessionsToRankAgainst opposingTeam, originalLevelID, levelMajorVersion, (err, sessionsToRankAgainst) -> + if err? then return cb err, null + + taskPairs = generateTaskPairs(sessionsToRankAgainst, session) + sendEachTaskPairToTheQueue taskPairs, (taskPairError) -> + if taskPairError? then return cb taskPairError, null + cb null module.exports.createNewTask = (req, res) -> From 643140fc983ad017a56f700d946c3c5aae9449bc Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 22 Mar 2014 09:40:23 -0700 Subject: [PATCH 08/30] Updated createjs. --- vendor/scripts/easeljs-NEXT.combined.js | 65 +- vendor/scripts/preloadjs-NEXT.combined.js | 182 +++- vendor/scripts/soundjs-NEXT.combined.js | 1018 +++++++-------------- 3 files changed, 517 insertions(+), 748 deletions(-) diff --git a/vendor/scripts/easeljs-NEXT.combined.js b/vendor/scripts/easeljs-NEXT.combined.js index f25f23e63..9e51cf98c 100644 --- a/vendor/scripts/easeljs-NEXT.combined.js +++ b/vendor/scripts/easeljs-NEXT.combined.js @@ -5300,7 +5300,7 @@ var p = DisplayObject.prototype = new createjs.EventDispatcher(); * event. * @property onTick * @type {Function} - * @deprecatedtick + * @deprecated Use addEventListener and the "tick" event. */ /** @@ -5768,7 +5768,7 @@ var p = DisplayObject.prototype = new createjs.EventDispatcher(); * be used to transform positions between coordinate spaces, such as with {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}} * and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}. * @method getConcatenatedMatrix - * @param {Matrix2D} [mtx] A {{#crossLink "Matrix2D"}}{{/crossLink}} object to populate with the calculated values. + * @param {Matrix2D} [matrix] A {{#crossLink "Matrix2D"}}{{/crossLink}} object to populate with the calculated values. * If null, a new Matrix2D object is returned. * @return {Matrix2D} a concatenated Matrix2D object representing the combined transform of the display object and * all of its parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}). @@ -7012,14 +7012,6 @@ var p = Stage.prototype = new createjs.Container(); * @default false **/ p.mouseMoveOutside = false; - - // TODO: deprecated. - /** - * Replaced by {{#crossLink "Stage/relayEventsTo"}}{{/crossLink}}. - * @property nextStage - * @type Stage - * @deprecated Use relayEventsTo instead. - **/ /** * The hitArea property is not supported for Stage. @@ -9794,18 +9786,17 @@ var p = SpriteSheetBuilder.prototype = new createjs.EventDispatcher; * source to draw to the frame. If not specified, it will look for a getBounds method, bounds property, * or nominalBounds property on the source to use. If one is not found, the frame will be skipped. * @param {Number} [scale=1] Optional. The scale to draw this frame at. Default is 1. - * @param {Function} [setupFunction] Optional. A function to call immediately before drawing this frame. - * @param {Array} [setupParams] Parameters to pass to the setup function. - * @param {Object} [setupScope] The scope to call the setupFunction in. + * @param {Function} [setupFunction] A function to call immediately before drawing this frame. It will be called with two parameters: the source, and setupData. + * @param {Object} [setupData] Arbitrary setup data to pass to setupFunction as the second parameter. * @return {Number} The index of the frame that was just added, or null if a sourceRect could not be determined. **/ - p.addFrame = function(source, sourceRect, scale, setupFunction, setupParams, setupScope) { + p.addFrame = function(source, sourceRect, scale, setupFunction, setupData) { if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; } var rect = sourceRect||source.bounds||source.nominalBounds; if (!rect&&source.getBounds) { rect = source.getBounds(); } if (!rect) { return null; } scale = scale||1; - return this._frames.push({source:source, sourceRect:rect, scale:scale, funct:setupFunction, params:setupParams, scope:setupScope, index:this._frames.length, height:rect.height*scale})-1; + return this._frames.push({source:source, sourceRect:rect, scale:scale, funct:setupFunction, data:setupData, index:this._frames.length, height:rect.height*scale})-1; }; /** @@ -9825,37 +9816,35 @@ var p = SpriteSheetBuilder.prototype = new createjs.EventDispatcher; }; /** - * This will take a MovieClip, and add its frames and labels to this builder. Labels will be added as an animation + * This will take a MovieClip instance, and add its frames and labels to this builder. Labels will be added as an animation * running from the label index to the next label. For example, if there is a label named "foo" at frame 0 and a label * named "bar" at frame 10, in a MovieClip with 15 frames, it will add an animation named "foo" that runs from frame * index 0 to 9, and an animation named "bar" that runs from frame index 10 to 14. * * Note that this will iterate through the full MovieClip with actionsEnabled set to false, ending on the last frame. * @method addMovieClip - * @param {MovieClip} source The source MovieClip to add to the sprite sheet. + * @param {MovieClip} source The source MovieClip instance to add to the sprite sheet. * @param {Rectangle} [sourceRect] A {{#crossLink "Rectangle"}}{{/crossLink}} defining the portion of the source to * draw to the frame. If not specified, it will look for a getBounds method, frameBounds * Array, bounds property, or nominalBounds property on the source to use. If one is not * found, the MovieClip will be skipped. * @param {Number} [scale=1] The scale to draw the movie clip at. + * @param {Function} [setupFunction] A function to call immediately before drawing each frame. It will be called with three parameters: the source, setupData, and the frame index. + * @param {Object} [setupData] Arbitrary setup data to pass to setupFunction as the second parameter. + * @param {Function} [labelFunction] This method will be called for each movieclip label that is added with four parameters: the label name, the source movieclip instance, the starting frame index (in the movieclip timeline) and the end index. It must return a new name for the label/animation, or false to exclude the label. **/ - p.addMovieClip = function(source, sourceRect, scale) { + p.addMovieClip = function(source, sourceRect, scale, setupFunction, setupData, labelFunction) { if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; } var rects = source.frameBounds; var rect = sourceRect||source.bounds||source.nominalBounds; if (!rect&&source.getBounds) { rect = source.getBounds(); } - if (!rect && !rects) { return null; } + if (!rect && !rects) { return; } - var baseFrameIndex = this._frames.length; + var i, l, baseFrameIndex = this._frames.length; var duration = source.timeline.duration; - for (var i=0; iExample + * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(3); // Set a higher number to load multiple items at once + * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order + * queue.loadManifest([ + * "script1.js", + * "script2.js", + * "image.png", // Load any time + * {src: "image2.png", maintainOrder: true} // Will wait for script2.js + * "image3.png", + * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) + * ]); + * * @property maintainScriptOrder * @type {Boolean} * @default true @@ -2247,6 +2269,11 @@ TODO: WINDOWS ISSUES * of types using the extension. Supported types are defined on LoadQueue, such as LoadQueue.IMAGE. * It is recommended that a type is specified when a non-standard file URI (such as a php script) us used. *
  • id: A string identifier which can be used to reference the loaded object.
  • + *
  • maintainOrder: Set to `true` to ensure this asset loads in the order defined in the manifest. This + * will happen when the max connections has been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}), + * and will only affect other assets also defined as `maintainOrder`. Everything else will finish as it is + * loaded. Ordered items are combined with script tags loading in order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} + * is set to `true`.
  • *
  • callback: Optional, used for JSONP requests, to define what method to call when the JSONP is loaded.
  • *
  • data: An arbitrary data object, which is included with the loaded object
  • *
  • method: used to define if this request uses GET or POST when sending data to the server. The default @@ -2314,9 +2341,14 @@ TODO: WINDOWS ISSUES *
  • src: The source of the file that is being loaded. This property is required. The source can * either be a string (recommended), or an HTML tag.
  • *
  • type: The type of file that will be loaded (image, sound, json, etc). PreloadJS does auto-detection - * of types using the extension. Supported types are defined on LoadQueue, such as LoadQueue.IMAGE. + * of types using the extension. Supported types are defined on LoadQueue, such as {{#crossLink "LoadQueue/IMAGE:property"}}{{/crossLink}}. * It is recommended that a type is specified when a non-standard file URI (such as a php script) us used.
  • *
  • id: A string identifier which can be used to reference the loaded object.
  • + *
  • maintainOrder: Set to `true` to ensure this asset loads in the order defined in the manifest. This + * will happen when the max connections has been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}), + * and will only affect other assets also defined as `maintainOrder`. Everything else will finish as it is + * loaded. Ordered items are combined with script tags loading in order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} + * is set to `true`.
  • *
  • callback: Optional, used for JSONP requests, to define what method to call when the JSONP is loaded.
  • *
  • data: An arbitrary data object, which is included with the loaded object
  • *
  • method: used to define if this request uses GET or POST when sending data to the server. The default @@ -2499,6 +2531,7 @@ TODO: WINDOWS ISSUES if (item == null) { return; } // Sometimes plugins or types should be skipped. var loader = this._createLoader(item); if (loader != null) { + item._loader = loader; this._loadQueue.push(loader); this._loadQueueBackup.push(loader); @@ -2506,9 +2539,11 @@ TODO: WINDOWS ISSUES this._updateProgress(); // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. - if (this.maintainScriptOrder + if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT - && loader instanceof createjs.XHRLoader) { + //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way + ) + || item.maintainOrder === true) { this._scriptOrder.push(item); this._loadedScripts.push(null); } @@ -2717,13 +2752,9 @@ TODO: WINDOWS ISSUES if (this._currentLoads.length >= this._maxConnections) { break; } var loader = this._loadQueue[i]; - // Determine if we should be only loading one at a time: - if (this.maintainScriptOrder - && loader instanceof createjs.TagLoader - && loader.getItem().type == createjs.LoadQueue.JAVASCRIPT) { - if (this._currentlyLoadingScript) { continue; } // Later items in the queue might not be scripts. - this._currentlyLoadingScript = true; - } + // Determine if we should be only loading one tag-script at a time: + // Note: maintainOrder items don't do anything here because we can hold onto their loaded value + if (!this._canStartLoad(loader)) { continue; } this._loadQueue.splice(i, 1); i--; this._loadItem(loader); @@ -2755,6 +2786,8 @@ TODO: WINDOWS ISSUES p._handleFileError = function(event) { var loader = event.target; this._numItemsLoaded++; + + this._finishOrderedItem(loader, true); this._updateProgress(); var newEvent = new createjs.Event("error"); @@ -2787,47 +2820,43 @@ TODO: WINDOWS ISSUES this._loadedRawResults[item.id] = loader.getResult(true); } + // Clean up the load item this._removeLoadItem(loader); - // Ensure that script loading happens in the right order. - if (this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) { - if (loader instanceof createjs.TagLoader) { - this._currentlyLoadingScript = false; - } else { - this._loadedScripts[createjs.indexOf(this._scriptOrder, item)] = item; - this._checkScriptLoadOrder(loader); - return; - } + if (!this._finishOrderedItem(loader)) { + // The item was NOT managed, so process it now + this._processFinishedLoad(item, loader); } - - // Clean up the load item - delete item._loadAsJSONP; - - // If the item was a manifest, then - if (item.type == createjs.LoadQueue.MANIFEST) { - var result = loader.getResult(); - if (result != null && result.manifest !== undefined) { - this.loadManifest(result, true); - } - } - - this._processFinishedLoad(item, loader); }; /** - * @method _processFinishedLoad - * @param {Object} item + * Flag an item as finished. If the item's order is being managed, then set it up to finish + * @method _finishOrderedItem * @param {AbstractLoader} loader - * @protected + * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate + * behaviour if it is. + * @private */ - p._processFinishedLoad = function(item, loader) { - // Old handleFileTagComplete follows here. - this._numItemsLoaded++; + p._finishOrderedItem = function(loader, loadFailed) { + var item = loader.getItem(); - this._updateProgress(); - this._sendFileComplete(item, loader); + if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) + || item.maintainOrder) { - this._loadNext(); + //TODO: Evaluate removal of the _currentlyLoadingScript + if (loader instanceof createjs.TagLoader && item.type == createjs.LoadQueue.JAVASCRIPT) { + this._currentlyLoadingScript = false; + } + + var index = createjs.indexOf(this._scriptOrder, item); + if (index == -1) { return false; } // This loader no longer exists + this._loadedScripts[index] = (loadFailed === true) ? true : item; + + this._checkScriptLoadOrder(); + return true; + } + + return false; }; /** @@ -2845,17 +2874,68 @@ TODO: WINDOWS ISSUES for (var i=0;ibefore + * the script can even be started, since it exist in the DOM while loading. + * @method _canStartLoad + * @param {XHRLoader|TagLoader} loader The loader for the item + * @return {Boolean} Whether the item can start a load or not. + * @private + */ + p._canStartLoad = function(loader) { + if (!this.maintainScriptOrder || loader instanceof createjs.XHRLoader) { return true; } + var item = loader.getItem(); + if (item.type != createjs.LoadQueue.JAVASCRIPT) { return true; } + if (this._currentlyLoadingScript) { return false; } + + var index = this._scriptOrder.indexOf(item); + var i = 0; + while (i < index) { + var checkItem = this._loadedScripts[i]; + if (checkItem == null) { return false; } + i++; + } + this._currentlyLoadingScript = true; + return true; + }; + /** * A load item is completed or was canceled, and needs to be removed from the LoadQueue. * @method _removeLoadItem @@ -2863,6 +2943,10 @@ TODO: WINDOWS ISSUES * @private */ p._removeLoadItem = function(loader) { + var item = loader.getItem(); + delete item._loader; + delete item._loadAsJSONP; + var l = this._currentLoads.length; for (var i=0;iBrowser Support - * Audio will work in browsers which support HTMLAudioElement (http://caniuse.com/audio) - * or WebAudio (http://caniuse.com/audio-api). A Flash fallback can be added + * Audio will work in browsers which support WebAudio (http://caniuse.com/audio-api) + * or HTMLAudioElement (http://caniuse.com/audio). A Flash fallback can be added * as well, which will work in any browser that supports the Flash player. * @module SoundJS * @main SoundJS @@ -931,11 +997,6 @@ this.createjs = this.createjs || {}; "use strict"; - //TODO: Interface to validate plugins and throw warnings - //TODO: Determine if methods exist on a plugin before calling // OJR this is only an issue if something breaks or user changes something - //TODO: Interface to validate instances and throw warnings - //TODO: Surface errors on audio from all plugins - //TODO: Timeouts // OJR for? /** * The Sound class is the public API for creating sounds, controlling the overall sound levels, and managing plugins. * All Sound APIs on this class are static. @@ -945,7 +1006,7 @@ this.createjs = this.createjs || {}; * or register multiple sounds using {{#crossLink "Sound/registerManifest"}}{{/crossLink}}. If you don't register a * sound prior to attempting to play it using {{#crossLink "Sound/play"}}{{/crossLink}} or create it using {{#crossLink "Sound/createInstance"}}{{/crossLink}}, * the sound source will be automatically registered but playback will fail as the source will not be ready. If you use - * PreloadJS, this is handled for you when the sound is + * PreloadJS, registration is handled for you when the sound is * preloaded. It is recommended to preload sounds either internally using the register functions or externally using * PreloadJS so they are ready when you want to use them. * @@ -982,11 +1043,12 @@ this.createjs = this.createjs || {}; * * Sound can be used as a plugin with PreloadJS to help preload audio properly. Audio preloaded with PreloadJS is * automatically registered with the Sound class. When audio is not preloaded, Sound will do an automatic internal - * load. As a result, it may not play immediately the first time play is called. Use the + * load. As a result, it may fail to play the first time play is called if the audio is not finished loading. Use the * {{#crossLink "Sound/fileload"}}{{/crossLink}} event to determine when a sound has finished internally preloading. * It is recommended that all audio is preloaded before it is played. * - * createjs.PreloadJS.installPlugin(createjs.Sound); + * var queue = new createjs.LoadQueue(); + * queue.installPlugin(createjs.Sound); * * Mobile Safe Approach
    * Mobile devices require sounds to be played inside of a user initiated event (touch/click) in varying degrees. @@ -1009,6 +1071,7 @@ this.createjs = this.createjs || {}; * when or how you apply the volume change, as the tag seems to need to play to apply it.
  • *
  • MP3 encoding will not always work for audio tags, particularly in Internet Explorer. We've found default * encoding with 64kbps works.
  • + *
  • Occasionally very short samples will get cut off.
  • *
  • There is a limit to how many audio tags you can load and play at once, which appears to be determined by * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate.
  • * @@ -1044,19 +1107,16 @@ this.createjs = this.createjs || {}; var s = Sound; + // TODO DEPRECATED /** - * DEPRECATED - * This approach has is being replaced by {{#crossLink "Sound/alternateExtensions:property"}}{{/crossLink}}, and - * support will be removed in the next version. - * - * The character (or characters) that are used to split multiple paths from an audio source. + * REMOVED + * Use {{#crossLink "Sound/alternateExtensions:property"}}{{/crossLink}} instead * @property DELIMITER * @type {String} * @default | * @static * @deprecated */ - s.DELIMITER = "|"; /** * The interrupt value to interrupt any currently playing instance with the same source, if the maximum number of @@ -1159,7 +1219,7 @@ this.createjs = this.createjs || {}; * @default ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"] * @since 0.4.0 */ - s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]; // OJR FlashPlugin does not currently support + s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]; /** * Some extensions use another type of extension support to play (one of them is a codex). This allows you to map @@ -1346,16 +1406,6 @@ this.createjs = this.createjs || {}; * @since 0.4.1 */ - //TODO: Deprecated - /** - * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "Sound/fileload:event"}}{{/crossLink}} - * event. - * @property onLoadComplete - * @type {Function} - * @deprecated Use addEventListener and the fileload event. - * @since 0.4.0 - */ - /** * Used by external plugins to dispatch file load events. * @method _sendFileLoadEvent @@ -1406,33 +1456,7 @@ this.createjs = this.createjs || {}; }; /** - * Deprecated in favor of {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} with a single argument. - * createjs.Sound.registerPlugins([createjs.WebAudioPlugin]); - * - * @method registerPlugin - * @param {Object} plugin The plugin class to install. - * @return {Boolean} Whether the plugin was successfully initialized. - * @static - * @deprecated - */ - s.registerPlugin = function (plugin) { - try { - console.log("createjs.Sound.registerPlugin has been deprecated. Please use registerPlugins."); - } catch (err) { - // you are in IE with the console closed, you monster - } - return s._registerPlugin(plugin); - }; - - /** - * Register a Sound plugin. Plugins handle the actual playback of audio. The default plugins are - * ({{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}), - * and are installed if no other plugins are present when the user attempts to start playback or register sound. - *

    Example

    - * createjs.FlashPlugin.swfPath = "../src/SoundJS/"; - * createjs.Sound._registerPlugin(createjs.FlashPlugin); - * - * To register multiple plugins, use {{#crossLink "Sound/registerPlugins"}}{{/crossLink}}. + * Used by {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} to register a Sound plugin. * * @method _registerPlugin * @param {Object} plugin The plugin class to install. @@ -1441,14 +1465,9 @@ this.createjs = this.createjs || {}; * @private */ s._registerPlugin = function (plugin) { - s._pluginsRegistered = true; - if (plugin == null) { - return false; - } // Note: Each plugin is passed in as a class reference, but we store the activePlugin as an instance if (plugin.isSupported()) { s.activePlugin = new plugin(); - //TODO: Check error on initialization return true; } return false; @@ -1467,9 +1486,9 @@ this.createjs = this.createjs || {}; * @static */ s.registerPlugins = function (plugins) { + s._pluginsRegistered = true; for (var i = 0, l = plugins.length; i < l; i++) { - var plugin = plugins[i]; - if (s._registerPlugin(plugin)) { + if (s._registerPlugin(plugins[i])) { return true; } } @@ -1489,15 +1508,9 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.initializeDefaultPlugins = function () { - if (s.activePlugin != null) { - return true; - } - if (s._pluginsRegistered) { - return false; - } - if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) { - return true; - } + if (s.activePlugin != null) {return true;} + if (s._pluginsRegistered) {return false;} + if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) {return true;} return false; }; @@ -1544,9 +1557,7 @@ this.createjs = this.createjs || {}; * @static */ s.getCapabilities = function () { - if (s.activePlugin == null) { - return null; - } + if (s.activePlugin == null) {return null;} return s.activePlugin._capabilities; }; @@ -1564,9 +1575,7 @@ this.createjs = this.createjs || {}; * @see getCapabilities */ s.getCapability = function (key) { - if (s.activePlugin == null) { - return null; - } + if (s.activePlugin == null) {return null;} return s.activePlugin._capabilities[key]; }; @@ -1581,19 +1590,64 @@ this.createjs = this.createjs || {}; * @param {Number|String|Boolean|Object} [data] Data associated with the item. Sound uses the data parameter as the * number of channels for an audio instance, however a "channels" property can be appended to the data object if * this property is used for other information. The audio channels will default to 1 if no value is found. - * @param {String} [path] A combined basepath and subPath from PreloadJS that has already been prepended to src. * @return {Boolean|Object} An object with the modified values of those that were passed in, or false if the active * plugin can not play the audio type. * @protected * @static */ - s.initLoad = function (src, type, id, data, path) { - // remove path from src so we can continue to support "|" splitting of src files // TODO remove this when "|" is removed - src = src.replace(path, ""); - var details = s.registerSound(src, id, data, false, path); - if (details == null) { - return false; + s.initLoad = function (src, type, id, data) { + return s._registerSound(src, id, data); + }; + + /** + * Internal method for loading sounds. This should not be called directly. + * + * @method _registerSound + * @param {String | Object} src The source to load. + * @param {String} [id] An id specified by the user to play the sound later. + * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of + * channels for an audio instance, however a "channels" property can be appended to the data object if it is used + * for other information. The audio channels will set a default based on plugin if no value is found. + * @return {Object} An object with the modified values that were passed in, which defines the sound. + * Returns false if the source cannot be parsed or no plugins can be initialized. + * Returns true if the source is already loaded. + * @static + * @private + * @since 0.5.3 + */ + + s._registerSound = function (src, id, data) { + if (!s.initializeDefaultPlugins()) {return false;} + + var details = s._parsePath(src, "sound", id, data); + if (details == null) {return false;} + + if (id != null) {s._idHash[id] = details.src;} + + var numChannels = s.activePlugin.defaultNumChannels || null; + if (data != null) { + if (!isNaN(data.channels)) { + numChannels = parseInt(data.channels); + } + else if (!isNaN(data)) { + numChannels = parseInt(data); + } } + var loader = s.activePlugin.register(details.src, numChannels); // Note only HTML audio uses numChannels + + SoundChannel.create(details.src, numChannels); + + // return the number of instances to the user. This will also be returned in the load event. + if (data == null || !isNaN(data)) { + details.data = numChannels || SoundChannel.maxPerChannel(); + } else { + details.data.channels = numChannels || SoundChannel.maxPerChannel(); + } + + details.tag = loader.tag; + if (loader.completeHandler) {details.completeHandler = loader.completeHandler;} + if (loader.type) {details.type = loader.type;} + return details; }; @@ -1613,8 +1667,6 @@ this.createjs = this.createjs || {}; * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of * channels for an audio instance, however a "channels" property can be appended to the data object if it is used * for other information. The audio channels will set a default based on plugin if no value is found. - * @param {Boolean} [preload=true] If the sound should be internally preloaded so that it can be played back - * without an external preloader. This is currently used by PreloadJS when loading sounds to disable internal preloading. * @param {string} basePath Set a path that will be prepended to src for loading. * @return {Object} An object with the modified values that were passed in, which defines the sound. * Returns false if the source cannot be parsed or no plugins can be initialized. @@ -1622,90 +1674,27 @@ this.createjs = this.createjs || {}; * @static * @since 0.4.0 */ - s.registerSound = function (src, id, data, preload, basePath) { - if (!s.initializeDefaultPlugins()) { - return false; - } - + s.registerSound = function (src, id, data, basePath) { if (src instanceof Object) { - basePath = id; //this assumes preload has not be passed in as a property // OJR check if arguments == 3 would be less fragile - //?? preload = src.preload; - // OJR refactor how data is passed in to make the parameters work better + basePath = id; id = src.id; data = src.data; src = src.src; } - // branch to different parse based on alternate formats setting - if (s.alternateExtensions.length) { - var details = s._parsePath2(src, "sound", id, data); + if (basePath != null) {src = basePath + src;} + + var details = s._registerSound(src, id, data); + + if(!details) {return false;} + + if (!s._preloadHash[details.src]) { s._preloadHash[details.src] = [];} + s._preloadHash[details.src].push({src:src, id:id, data:details.data}); + if (s._preloadHash[details.src].length == 1) { + // OJR note this will disallow reloading a sound if loading fails or the source changes + s.activePlugin.preload(details.src, details.tag); } else { - var details = s._parsePath(src, "sound", id, data); - } - if (details == null) { - return false; - } - if (basePath != null) { - src = basePath + src; - details.src = basePath + details.src; - } - - if (id != null) { - s._idHash[id] = details.src; - } - - var numChannels = null; // null tells SoundChannel to set this to it's internal maxDefault - if (data != null) { - if (!isNaN(data.channels)) { - numChannels = parseInt(data.channels); - } - else if (!isNaN(data)) { - numChannels = parseInt(data); - } - } - var loader = s.activePlugin.register(details.src, numChannels); // Note only HTML audio uses numChannels - - if (loader != null) { // all plugins currently return a loader - if (loader.numChannels != null) { - numChannels = loader.numChannels; - } // currently only HTMLAudio returns this - SoundChannel.create(details.src, numChannels); - - // return the number of instances to the user. This will also be returned in the load event. - if (data == null || !isNaN(data)) { - data = details.data = numChannels || SoundChannel.maxPerChannel(); - } else { - data.channels = details.data.channels = numChannels || SoundChannel.maxPerChannel(); - } - - // If the loader returns a tag, return it instead for preloading. - // OJR all loaders currently use tags? - if (loader.tag != null) { - details.tag = loader.tag; - } else if (loader.src) { - details.src = loader.src; - } - // If the loader returns a complete handler, pass it on to the prelaoder. - if (loader.completeHandler != null) { - details.completeHandler = loader.completeHandler; - } - if (loader.type) { - details.type = loader.type; - } - } - - if (preload != false) { - if (!s._preloadHash[details.src]) { - s._preloadHash[details.src] = []; - } // we do this so we can store multiple id's and data if needed - s._preloadHash[details.src].push({src:src, id:id, data:data}); // keep this data so we can return it in fileload event - if (s._preloadHash[details.src].length == 1) { - // if already loaded once, don't load a second time // OJR note this will disallow reloading a sound if loading fails or the source changes - s.activePlugin.preload(details.src, loader); - } else { - // if src already loaded successfully, return true - if (s._preloadHash[details.src][0] == true) {return true;} - } + if (s._preloadHash[details.src][0] == true) {return true;} } return details; @@ -1741,8 +1730,8 @@ this.createjs = this.createjs || {}; s.registerManifest = function (manifest, basePath) { var returnValues = []; for (var i = 0, l = manifest.length; i < l; i++) { - returnValues[i] = createjs.Sound.registerSound(manifest[i].src, manifest[i].id, manifest[i].data, manifest[i].preload, basePath); - } // OJR consider removing .preload from args, as it is only used by PreloadJS + returnValues[i] = createjs.Sound.registerSound(manifest[i].src, manifest[i].id, manifest[i].data, basePath); + } return returnValues; }; @@ -1764,27 +1753,16 @@ this.createjs = this.createjs || {}; * @since 0.4.1 */ s.removeSound = function(src, basePath) { - if (s.activePlugin == null) { - return false; - } + if (s.activePlugin == null) {return false;} - if (src instanceof Object) { - src = src.src; - } + if (src instanceof Object) {src = src.src;} src = s._getSrcById(src); + if (basePath != null) {src = basePath + src;} - if (s.alternateExtensions.length) { - var details = s._parsePath2(src); - } else { - var details = s._parsePath(src); - } - if (details == null) { - return false; - } - if (basePath != null) {details.src = basePath + details.src;} + var details = s._parsePath(src); + if (details == null) {return false;} src = details.src; - // remove src from _idHash // Note "for in" can be a slow operation for(var prop in s._idHash){ if(s._idHash[prop] == src) { delete(s._idHash[prop]); @@ -1794,10 +1772,8 @@ this.createjs = this.createjs || {}; // clear from SoundChannel, which also stops and deletes all instances SoundChannel.removeSrc(src); - // remove src from _preloadHash delete(s._preloadHash[src]); - // activePlugin cleanup s.activePlugin.removeSound(src); return true; @@ -1850,7 +1826,7 @@ this.createjs = this.createjs || {}; s._idHash = {}; s._preloadHash = {}; SoundChannel.removeAll(); - s.activePlugin.removeAllSounds(); + if (s.activePlugin) {s.activePlugin.removeAllSounds();} }; /** @@ -1869,11 +1845,7 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.loadComplete = function (src) { - if (s.alternateExtensions.length) { - var details = s._parsePath2(src, "sound"); - } else { - var details = s._parsePath(src, "sound"); - } + var details = s._parsePath(src, "sound"); if (details) { src = s._getSrcById(details.src); } else { @@ -1883,10 +1855,8 @@ this.createjs = this.createjs || {}; }; /** - * Parse the path of a sound, usually from a manifest item. Manifest items support single file paths, as well as - * composite paths using {{#crossLink "Sound/DELIMITER:property"}}{{/crossLink}}, which defaults to "|". The first path supported by the - * current browser/plugin will be used. - * NOTE the "|" approach is deprecated and will be removed in the next version + * Parse the path of a sound, usually from a manifest item. alternate extensions will be attempted in order if the + * current extension is not supported * @method _parsePath * @param {String} value The path to an audio source. * @param {String} [type] The type of path. This will typically be "sound" or null. @@ -1898,60 +1868,22 @@ this.createjs = this.createjs || {}; * @protected */ s._parsePath = function (value, type, id, data) { - if (typeof(value) != "string") {value = value.toString();} - var sounds = value.split(s.DELIMITER); - if (sounds.length > 1) { - try { - console.log("createjs.Sound.DELIMITER \"|\" loading approach has been deprecated. Please use the new alternateExtensions property."); - } catch (err) { - // you are in IE with the console closed, you monster - } - } - var ret = {type:type || "sound", id:id, data:data}; - var c = s.getCapabilities(); - for (var i = 0, l = sounds.length; i < l; i++) { - var sound = sounds[i]; - - var match = sound.match(s.FILE_PATTERN); - if (match == null) { - return false; - } - var name = match[4]; - var ext = match[5]; - - if (c[ext] && createjs.indexOf(s.SUPPORTED_EXTENSIONS, ext) > -1) { - ret.name = name; - ret.src = sound; - ret.extension = ext; - return ret; - } - } - return null; - }; - - // new approach, when old approach is deprecated this will become _parsePath - s._parsePath2 = function (value, type, id, data) { if (typeof(value) != "string") {value = value.toString();} var match = value.match(s.FILE_PATTERN); - if (match == null) { - return false; - } + if (match == null) {return false;} + var name = match[4]; var ext = match[5]; - var c = s.getCapabilities(); var i = 0; while (!c[ext]) { ext = s.alternateExtensions[i++]; if (i > s.alternateExtensions.length) { return null;} // no extensions are supported } - value = value.replace("."+match[5], "."+ext); - var ret = {type:type || "sound", id:id, data:data}; - ret.name = name; - ret.src = value; - ret.extension = ext; + + var ret = {type:type || "sound", id:id, data:data, name:name, src:value, extension:ext}; return ret; }; @@ -1996,11 +1928,8 @@ this.createjs = this.createjs || {}; */ s.play = function (src, interrupt, delay, offset, loop, volume, pan) { var instance = s.createInstance(src); - var ok = s._playInstance(instance, interrupt, delay, offset, loop, volume, pan); - if (!ok) { - instance.playFailed(); - } + if (!ok) {instance.playFailed();} return instance; }; @@ -2026,27 +1955,17 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.createInstance = function (src) { - if (!s.initializeDefaultPlugins()) { - return s._defaultSoundInstance; - } + if (!s.initializeDefaultPlugins()) {return s._defaultSoundInstance;} src = s._getSrcById(src); - if (s.alternateExtensions.length) { - var details = s._parsePath2(src, "sound"); - } else { - var details = s._parsePath(src, "sound"); - } + var details = s._parsePath(src, "sound"); var instance = null; if (details != null && details.src != null) { - // make sure that we have a sound channel (sound is registered or previously played) SoundChannel.create(details.src); instance = s.activePlugin.create(details.src); } else { - // the src is not supported, so give back a dummy instance. - // This can happen if PreloadJS fails because the plugin does not support the ext, and was passed an id which - // will not get added to the _idHash. instance = Sound._defaultSoundInstance; } @@ -2068,13 +1987,11 @@ this.createjs = this.createjs || {}; * @static */ s.setVolume = function (value) { - if (Number(value) == null) { - return false; - } + if (Number(value) == null) {return false;} value = Math.max(0, Math.min(1, value)); s._masterVolume = value; if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) { - var instances = this._instances; // OJR does this impact garbage collection more than it helps performance? + var instances = this._instances; for (var i = 0, l = instances.length; i < l; i++) { instances[i].setMasterVolume(value); } @@ -2096,14 +2013,6 @@ this.createjs = this.createjs || {}; return s._masterVolume; }; - /** - * REMOVED. Please see {{#crossLink "Sound/setMute"}}{{/crossLink}}. - * @method mute - * @param {Boolean} value Whether the audio should be muted or not. - * @static - * @deprecated This function has been deprecated. Please use setMute instead. - */ - /** * Mute/Unmute all audio. Note that muted audio still plays at 0 volume. This global mute value is maintained * separately and when set will override, but not change the mute property of individual instances. To mute an individual @@ -2119,9 +2028,7 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.setMute = function (value) { - if (value == null || value == undefined) { - return false; - } + if (value == null) {return false;} this._masterMute = value; if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) { @@ -2205,15 +2112,13 @@ this.createjs = this.createjs || {}; interrupt = interrupt || s.defaultInterruptBehavior; if (delay == null) {delay = 0;} if (offset == null) {offset = instance.getPosition();} - if (loop == null) {loop = 0;} + if (loop == null) {loop = 0;} // OJR consider using instance._remainingLoops if (volume == null) {volume = instance.volume;} if (pan == null) {pan = instance.pan;} if (delay == 0) { var ok = s._beginPlaying(instance, interrupt, offset, loop, volume, pan); - if (!ok) { - return false; - } + if (!ok) {return false;} } else { //Note that we can't pass arguments to proxy OR setTimeout (IE only), so just wrap the function call. // OJR WebAudio may want to handle this differently, so it might make sense to move this functionality into the plugins in the future @@ -2251,11 +2156,8 @@ this.createjs = this.createjs || {}; } var result = instance._beginPlaying(offset, loop, volume, pan); if (!result) { - //LM: Should we remove this from the SoundChannel (see finishedPlaying) var index = createjs.indexOf(this._instances, instance); - if (index > -1) { - this._instances.splice(index, 1); - } + if (index > -1) {this._instances.splice(index, 1);} return false; } return true; @@ -2266,15 +2168,12 @@ this.createjs = this.createjs || {}; * instead. * @method _getSrcById * @param {String} value The ID the sound was registered with. - * @return {String} The source of the sound. Returns null if src has been registered with this id. + * @return {String} The source of the sound if it has been registered with this ID or the value that was passed in. * @protected * @static */ s._getSrcById = function (value) { - if (s._idHash == null || s._idHash[value] == null) { - return value; - } - return s._idHash[value]; + return s._idHash[value] || value; }; /** @@ -2289,9 +2188,7 @@ this.createjs = this.createjs || {}; s._playFinished = function (instance) { SoundChannel.remove(instance); var index = createjs.indexOf(this._instances, instance); - if (index > -1) { - this._instances.splice(index, 1); - } + if (index > -1) {this._instances.splice(index, 1);} // OJR this will always be > -1, there is no way for an instance to exist without being added to this._instances }; createjs.Sound = Sound; @@ -2352,10 +2249,8 @@ this.createjs = this.createjs || {}; */ SoundChannel.removeSrc = function (src) { var channel = SoundChannel.get(src); - if (channel == null) { - return false; - } - channel.removeAll(); // this stops and removes all active instances + if (channel == null) {return false;} + channel._removeAll(); // this stops and removes all active instances delete(SoundChannel.channels[src]); return true; }; @@ -2366,7 +2261,7 @@ this.createjs = this.createjs || {}; */ SoundChannel.removeAll = function () { for(var channel in SoundChannel.channels) { - SoundChannel.channels[channel].removeAll(); // this stops and removes all active instances + SoundChannel.channels[channel]._removeAll(); // this stops and removes all active instances } SoundChannel.channels = {}; }; @@ -2381,10 +2276,8 @@ this.createjs = this.createjs || {}; */ SoundChannel.add = function (instance, interrupt) { var channel = SoundChannel.get(instance.src); - if (channel == null) { - return false; - } - return channel.add(instance, interrupt); + if (channel == null) {return false;} + return channel._add(instance, interrupt); }; /** * Remove an instance from the channel. @@ -2395,10 +2288,8 @@ this.createjs = this.createjs || {}; */ SoundChannel.remove = function (instance) { var channel = SoundChannel.get(instance.src); - if (channel == null) { - return false; - } - channel.remove(instance); + if (channel == null) {return false;} + channel._remove(instance); return true; }; /** @@ -2461,9 +2352,7 @@ this.createjs = this.createjs || {}; p.init = function (src, max) { this.src = src; this.max = max || this.maxDefault; - if (this.max == -1) { - this.max = this.maxDefault; - } + if (this.max == -1) {this.max = this.maxDefault;} this._instances = []; }; @@ -2473,7 +2362,7 @@ this.createjs = this.createjs || {}; * @param {Number} index The index to return. * @return {SoundInstance} The SoundInstance at a specific instance. */ - p.get = function (index) { + p._get = function (index) { return this._instances[index]; }; @@ -2483,10 +2372,8 @@ this.createjs = this.createjs || {}; * @param {SoundInstance} instance The instance to add. * @return {Boolean} The success of the method call. If the channel is full, it will return false. */ - p.add = function (instance, interrupt) { - if (!this.getSlot(interrupt, instance)) { - return false; - } + p._add = function (instance, interrupt) { + if (!this._getSlot(interrupt, instance)) {return false;} this._instances.push(instance); this.length++; return true; @@ -2499,11 +2386,9 @@ this.createjs = this.createjs || {}; * @return {Boolean} The success of the remove call. If the instance is not found in this channel, it will * return false. */ - p.remove = function (instance) { + p._remove = function (instance) { var index = createjs.indexOf(this._instances, instance); - if (index == -1) { - return false; - } + if (index == -1) {return false;} this._instances.splice(index, 1); this.length--; return true; @@ -2513,8 +2398,8 @@ this.createjs = this.createjs || {}; * Stop playback and remove all instances from the channel. Usually in response to a delete call. * #method removeAll */ - p.removeAll = function () { - // Note that stop() removes the item from the list, but we don't want to assume that. + p._removeAll = function () { + // Note that stop() removes the item from the list for (var i=this.length-1; i>=0; i--) { this._instances[i].stop(); } @@ -2528,11 +2413,11 @@ this.createjs = this.createjs || {}; * @return {Boolean} Determines if there is an available slot. Depending on the interrupt mode, if there are no slots, * an existing SoundInstance may be interrupted. If there are no slots, this method returns false. */ - p.getSlot = function (interrupt, instance) { + p._getSlot = function (interrupt, instance) { var target, replacement; for (var i = 0, l = this.max; i < l; i++) { - target = this.get(i); + target = this._get(i); // Available Space if (target == null) { @@ -2554,16 +2439,15 @@ this.createjs = this.createjs || {}; replacement = target; // Audio is a better candidate than the current target, according to playhead - } else if ( - (interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) || - (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) { + } else if ( (interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) || + (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) { replacement = target; } } if (replacement != null) { replacement._interrupt(); - this.remove(replacement); + this._remove(replacement); return true; } return false; @@ -2720,9 +2604,7 @@ this.createjs = this.createjs || {}; // OJR isMobile may be redundant with _isFileXHRSupported available. Consider removing. if (location.protocol == "file:" && !isMobilePhoneGap && !this._isFileXHRSupported()) { return false; } // Web Audio requires XHR, which is not usually available locally s._generateCapabilities(); - if (s.context == null) { - return false; - } + if (s.context == null) {return false;} return true; }; @@ -2767,28 +2649,19 @@ this.createjs = this.createjs || {}; * @protected */ s._generateCapabilities = function () { - if (s._capabilities != null) { - return; - } - // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section, - // therefore tag is still required for the capabilities check + if (s._capabilities != null) {return;} + // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section var t = document.createElement("audio"); + if (t.canPlayType == null) {return null;} - if (t.canPlayType == null) { - return null; - } - - // This check is first because it's what is currently used, but the spec calls for it to be AudioContext so this - // will probably change in time - if (window.webkitAudioContext) { - s.context = new webkitAudioContext(); - } else if (window.AudioContext) { + if (window.AudioContext) { s.context = new AudioContext(); + } else if (window.webkitAudioContext) { + s.context = new webkitAudioContext(); } else { return null; } - // this handles if only deprecated Web Audio API calls are supported s._compatibilitySetUp(); // playing this inside of a touch event will enable audio on iOS, which starts muted @@ -2814,12 +2687,6 @@ this.createjs = this.createjs || {}; if (s.context.destination.numberOfChannels < 2) { s._capabilities.panning = false; } - - // set up AudioNodes that all of our source audio will connect to - s.dynamicsCompressorNode = s.context.createDynamicsCompressor(); - s.dynamicsCompressorNode.connect(s.context.destination); - s.gainNode = s.context.createGain(); - s.gainNode.connect(s.dynamicsCompressorNode); }; /** @@ -2829,10 +2696,12 @@ this.createjs = this.createjs || {}; * don't support new calls. * * @method _compatibilitySetUp + * @static * @protected * @since 0.4.2 */ s._compatibilitySetUp = function() { + s._panningModel = "equalpower"; //assume that if one new call is supported, they all are if (s.context.createGain) { return; } @@ -2845,7 +2714,7 @@ this.createjs = this.createjs || {}; audioNode.__proto__.stop = audioNode.__proto__.noteOff; // panningModel - this._panningModel = 0; + s._panningModel = 0; }; /** @@ -2855,24 +2724,18 @@ this.createjs = this.createjs || {}; * for example). * *

    Example

    - * * function handleTouch(event) { * createjs.WebAudioPlugin.playEmptySound(); * } * * @method playEmptySound + * @static * @since 0.4.1 */ s.playEmptySound = function() { - // create empty buffer - var buffer = this.context.createBuffer(1, 1, 22050); - var source = this.context.createBufferSource(); - source.buffer = buffer; - - // connect to output (your speakers) - source.connect(this.context.destination); - - // play the file + var source = s.context.createBufferSource(); + source.buffer = s.context.createBuffer(1, 1, 22050); + source.connect(s.context.destination); source.start(0, 0, 0); }; @@ -2888,7 +2751,6 @@ this.createjs = this.createjs || {}; * @default 1 * @protected */ - // TODO refactor Sound.js so we can use getter setter for volume p._volume = 1; /** @@ -2910,20 +2772,24 @@ this.createjs = this.createjs || {}; /** * A DynamicsCompressorNode, which is used to improve sound quality and prevent audio distortion. * It is connected to context.destination. + * + * Can be accessed by advanced users through createjs.Sound.activePlugin.dynamicsCompressorNode. * @property dynamicsCompressorNode * @type {AudioNode} */ p.dynamicsCompressorNode = null; /** - * A GainNode for controlling master _volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}. + * A GainNode for controlling master volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}. + * + * Can be accessed by advanced users through createjs.Sound.activePlugin.gainNode. * @property gainNode * @type {AudioGainNode} */ p.gainNode = null; /** - * An object hash used internally to store ArrayBuffers, indexed by the source URI used to load it. This + * An object hash used internally to store ArrayBuffers, indexed by the source URI used to load it. This * prevents having to load and decode audio files more than once. If a load has been started on a file, * arrayBuffers[src] will be set to true. Once load is complete, it is set the the loaded * ArrayBuffer instance. @@ -2943,8 +2809,13 @@ this.createjs = this.createjs || {}; this._arrayBuffers = {}; this.context = s.context; - this.gainNode = s.gainNode; - this.dynamicsCompressorNode = s.dynamicsCompressorNode; + this._panningModel = s._panningModel; + + // set up AudioNodes that all of our source audio will connect to + this.dynamicsCompressorNode = this.context.createDynamicsCompressor(); + this.dynamicsCompressorNode.connect(this.context.destination); + this.gainNode = this.context.createGain(); + this.gainNode.connect(this.dynamicsCompressorNode); }; /** @@ -2958,11 +2829,9 @@ this.createjs = this.createjs || {}; * @return {Object} A result object, containing a "tag" for preloading purposes. */ p.register = function (src, instances) { - this._arrayBuffers[src] = true; // This is needed for PreloadJS - var tag = new createjs.WebAudioPlugin.Loader(src, this); - return { - tag:tag - }; + this._arrayBuffers[src] = true; + var loader = {tag: new createjs.WebAudioPlugin.Loader(src, this)}; + return loader; }; /** @@ -3021,19 +2890,18 @@ this.createjs = this.createjs || {}; * @method _handlePreloadComplete * @protected */ - p._handlePreloadComplete = function () { - //LM: I would recommend having the Loader include an "event" in the onload, and properly binding this callback. - createjs.Sound._sendFileLoadEvent(this.src); // fire event or callback on Sound - // note "this" will reference Loader object + p._handlePreloadComplete = function (loader) { + createjs.Sound._sendFileLoadEvent(loader.src); + loader.cleanUp(); }; /** * Internally preload a sound. Loading uses XHR2 to load an array buffer for use with WebAudio. * @method preload * @param {String} src The sound URI to load. - * @param {Object} instance Not used in this plugin. + * @param {Object} tag Not used in this plugin. */ - p.preload = function (src, instance) { + p.preload = function (src, tag) { this._arrayBuffers[src] = true; var loader = new createjs.WebAudioPlugin.Loader(src, this); loader.onload = this._handlePreloadComplete; @@ -3047,9 +2915,7 @@ this.createjs = this.createjs || {}; * @return {SoundInstance} A sound instance for playback and control. */ p.create = function (src) { - if (!this.isPreloadStarted(src)) { - this.preload(src); - } + if (!this.isPreloadStarted(src)) {this.preload(src);} return new createjs.WebAudioPlugin.SoundInstance(src, this); }; @@ -3116,7 +2982,6 @@ this.createjs = this.createjs || {}; * for control by the user. * *

    Example

    - * * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3"); * * A number of additional parameters provide a quick way to determine how a sound is played. Please see the Sound @@ -3198,16 +3063,6 @@ this.createjs = this.createjs || {}; */ p._offset = 0; - /** - * The time in milliseconds before the sound starts. - * Note this is handled by {{#crossLink "Sound"}}{{/crossLink}}. - * @property _delay - * @type {Number} - * @default 0 - * @protected - */ - p._delay = 0; // OJR remove this property from SoundInstance as it is not used here? - /** * The volume of the sound, between 0 and 1. *
    Note this uses a getter setter, which is not supported by Firefox versions 3.6 or lower and Opera versions 11.50 or lower, @@ -3221,8 +3076,7 @@ this.createjs = this.createjs || {}; * @default 1 */ p._volume = 1; - // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors - try { + if (createjs.definePropertySupported) { Object.defineProperty(p, "volume", { get: function() { return this._volume; @@ -3234,9 +3088,7 @@ this.createjs = this.createjs || {}; this._updateVolume(); } }); - } catch (e) { - // dispatch message or error? - }; + } /** * The pan of the sound, between -1 (left) and 1 (right). Note that pan is not supported by HTML Audio. @@ -3250,8 +3102,7 @@ this.createjs = this.createjs || {}; * @default 0 */ p._pan = 0; - // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors - try { + if (createjs.definePropertySupported) { Object.defineProperty(p, "pan", { get: function() { return this._pan; @@ -3265,10 +3116,7 @@ this.createjs = this.createjs || {}; this.panNode.setPosition(value, 0, -0.5); // z need to be -0.5 otherwise the sound only plays in left, right, or center } }); - } catch (e) { - // dispatch message or error? - }; - + } /** * The length of the audio clip, in milliseconds. @@ -3291,7 +3139,7 @@ this.createjs = this.createjs || {}; /** * A Timeout created by {{#crossLink "Sound"}}{{/crossLink}} when this SoundInstance is played with a delay. - * This allows SoundInstance to remove the delay if stop or pause or cleanup are called before playback begins. + * This allows SoundInstance to remove the delay if stop, pause, or cleanup are called before playback begins. * @property _delayTimeoutId * @type {timeoutVariable} * @default null @@ -3432,43 +3280,6 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ - //TODO: Deprecated - /** - * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/succeeded:event"}}{{/crossLink}} - * event. - * @property onPlaySucceeded - * @type {Function} - * @deprecated Use addEventListener and the "succeeded" event. - */ - /** - * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/interrupted:event"}}{{/crossLink}} - * event. - * @property onPlayInterrupted - * @type {Function} - * @deprecated Use addEventListener and the "interrupted" event. - */ - /** - * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/failed:event"}}{{/crossLink}} - * event. - * @property onPlayFailed - * @type {Function} - * @deprecated Use addEventListener and the "failed" event. - */ - /** - * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/complete:event"}}{{/crossLink}} - * event. - * @property onComplete - * @type {Function} - * @deprecated Use addEventListener and the "complete" event. - */ - /** - * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/loop:event"}}{{/crossLink}} - * event. - * @property onLoop - * @type {Function} - * @deprecated Use addEventListener and the "loop" event. - */ - /** * A helper method that dispatches all events for SoundInstance. * @method _sendEvent @@ -3489,18 +3300,16 @@ this.createjs = this.createjs || {}; * @protected */ p._init = function (src, owner) { - this._owner = owner; this.src = src; + this._owner = owner; this.gainNode = this._owner.context.createGain(); - this.panNode = this._owner.context.createPanner(); //TODO test how this affects when we have mono audio + this.panNode = this._owner.context.createPanner(); this.panNode.panningModel = this._owner._panningModel; this.panNode.connect(this.gainNode); - if (this._owner.isPreloadComplete(this.src)) { - this._duration = this._owner._arrayBuffers[this.src].duration * 1000; - } + if (this._owner.isPreloadComplete(this.src)) {this._duration = this._owner._arrayBuffers[this.src].duration * 1000;} this._endedHandler = createjs.proxy(this._handleSoundComplete, this); }; @@ -3516,9 +3325,7 @@ this.createjs = this.createjs || {}; this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); } - if (this.gainNode.numberOfOutputs != 0) { - this.gainNode.disconnect(0); - } // this works because we only have one connection, and it returns 0 if we've already disconnected it. + if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);} // OJR there appears to be a bug that this doesn't always work in webkit (Chrome and Safari). According to the documentation, this should work. clearTimeout(this._delayTimeoutId); // clear timeout that plays delayed sound @@ -3526,9 +3333,6 @@ this.createjs = this.createjs || {}; this._startTime = 0; // This is used by getPosition - if (window.createjs == null) { - return; - } createjs.Sound._playFinished(this); }; @@ -3544,7 +3348,7 @@ this.createjs = this.createjs || {}; if(audioNode) { audioNode.stop(0); audioNode.disconnect(this.panNode); - audioNode = null; // release reference so Web Audio can handle removing references and garbage collection + audioNode = null; } return audioNode; }; @@ -3567,11 +3371,7 @@ this.createjs = this.createjs || {}; * @protected */ p._handleSoundReady = function (event) { - if (window.createjs == null) { - return; - } - - if ((this._offset*1000) > this.getDuration()) { // converting offset to ms + if ((this._offset*1000) > this.getDuration()) { this.playFailed(); return; } else if (this._offset < 0) { // may not need this check if play ignores negative values, this is not specified in the API http://www.w3.org/TR/webaudio/#AudioBufferSourceNode @@ -3609,7 +3409,7 @@ this.createjs = this.createjs || {}; audioNode.buffer = this._owner._arrayBuffers[this.src]; audioNode.connect(this.panNode); var currentTime = this._owner.context.currentTime; - audioNode.startTime = startTime + audioNode.buffer.duration; //currentTime + audioNode.buffer.duration - (currentTime - startTime); + audioNode.startTime = startTime + audioNode.buffer.duration; audioNode.start(audioNode.startTime, offset, audioNode.buffer.duration - offset); return audioNode; }; @@ -3654,14 +3454,6 @@ this.createjs = this.createjs || {}; * @protected */ p._beginPlaying = function (offset, loop, volume, pan) { - if (window.createjs == null) { - return; - } - - if (!this.src) { - return; - } - this._offset = offset / 1000; //convert ms to sec this._remainingLoops = loop; this.volume = volume; @@ -3689,22 +3481,19 @@ this.createjs = this.createjs || {}; * @return {Boolean} If the pause call succeeds. This will return false if the sound isn't currently playing. */ p.pause = function () { - if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this.paused = this._paused = true; + if (this._paused || this.playState != createjs.Sound.PLAY_SUCCEEDED) {return false;} - this._offset = this._owner.context.currentTime - this._startTime; // this allows us to restart the sound at the same point in playback - this.sourceNode = this._cleanUpAudioNode(this.sourceNode); - this.sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); + this.paused = this._paused = true; - if (this.gainNode.numberOfOutputs != 0) { - this.gainNode.disconnect(); - } // this works because we only have one connection, and it returns 0 if we've already disconnected it. + this._offset = this._owner.context.currentTime - this._startTime; // this allows us to restart the sound at the same point in playback + this.sourceNode = this._cleanUpAudioNode(this.sourceNode); + this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); - clearTimeout(this._delayTimeoutId); // clear timeout that plays delayed sound - clearTimeout(this._soundCompleteTimeout); // clear timeout that triggers sound complete - return true; - } - return false; + if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect();} + + clearTimeout(this._delayTimeoutId); + clearTimeout(this._soundCompleteTimeout); + return true; }; /** @@ -3721,10 +3510,8 @@ this.createjs = this.createjs || {}; * @return {Boolean} If the resume call succeeds. This will return false if called on a sound that is not paused. */ p.resume = function () { - if (!this._paused) { - return false; - } - this._handleSoundReady(null); + if (!this._paused) {return false;} + this._handleSoundReady(); return true; }; @@ -3764,23 +3551,20 @@ this.createjs = this.createjs || {}; */ p.setVolume = function (value) { this.volume = value; - return true; // This is always true because even if the volume is not updated, the value is set + return true; }; /** * Internal function used to update the volume based on the instance volume, master volume, instance mute value, * and master mute value. * @method _updateVolume - * @return {Boolean} if the volume was updated. * @protected */ p._updateVolume = function () { var newVolume = this._muted ? 0 : this._volume; if (newVolume != this.gainNode.gain.value) { this.gainNode.gain.value = newVolume; - return true; } - return false; }; /** @@ -3810,9 +3594,7 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ p.setMute = function (value) { - if (value == null || value == undefined) { - return false; - } + if (value == null) {return false;} this._muted = value; this._updateVolume(); @@ -3852,6 +3634,7 @@ this.createjs = this.createjs || {}; p.setPan = function (value) { this.pan = value; // Unfortunately panner does not give us a way to access this after it is set http://www.w3.org/TR/webaudio/#AudioPannerNode if(this.pan != value) {return false;} + return true; }; /** @@ -3912,9 +3695,7 @@ this.createjs = this.createjs || {}; clearTimeout(this._soundCompleteTimeout); // clear timeout that triggers sound complete } // NOTE we cannot just call cleanup because it also calls the Sound function _playFinished which releases this instance in SoundChannel - if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this._handleSoundReady(null); - } + if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) {this._handleSoundReady();} return true; }; @@ -3960,16 +3741,13 @@ this.createjs = this.createjs || {}; this._soundCompleteTimeout = setTimeout(this._endedHandler, this._duration); } else { - this._handleSoundReady(null); + this._handleSoundReady(); } this._sendEvent("loop"); return; } - if (window.createjs == null) { - return; - } this._cleanUp(); this.playState = createjs.Sound.PLAY_FINISHED; this._sendEvent("complete"); @@ -3977,9 +3755,6 @@ this.createjs = this.createjs || {}; // Play has failed, which can happen for a variety of reasons. p.playFailed = function () { - if (window.createjs == null) { - return; - } this._cleanUp(); this.playState = createjs.Sound.PLAY_FAILED; this._sendEvent("failed"); @@ -4023,13 +3798,6 @@ this.createjs = this.createjs || {}; */ p.src = null; - /** - * The original source of the sound, before it is altered with a basePath. - * #property src - * @type {String} - */ - p.originalSrc = null; - /** * The decoded AudioBuffer array that is returned when loading is complete. * #property result @@ -4054,17 +3822,16 @@ this.createjs = this.createjs || {}; p.onprogress = null; /** - * The callback that fires if the load hits an error. - * #property onError + * The callback that fires if the load hits an error. This follows HTML tag naming. + * #property onerror * @type {Method} * @protected */ - p.onError = null; + p.onerror = null; // constructor p._init = function (src, owner) { this.src = src; - this.originalSrc = src; this.owner = owner; }; @@ -4074,16 +3841,13 @@ this.createjs = this.createjs || {}; * @param {String} src The path to the sound. */ p.load = function (src) { - if (src != null) { - // TODO does this need to set this.originalSrc - this.src = src; - } + if (src != null) {this.src = src;} this.request = new XMLHttpRequest(); this.request.open("GET", this.src, true); this.request.responseType = "arraybuffer"; this.request.onload = createjs.proxy(this.handleLoad, this); - this.request.onError = createjs.proxy(this.handleError, this); + this.request.onerror = createjs.proxy(this.handleError, this); this.request.onprogress = createjs.proxy(this.handleProgress, this); this.request.send(); @@ -4101,7 +3865,7 @@ this.createjs = this.createjs || {}; */ p.handleProgress = function (loaded, total) { this.progress = loaded / total; - this.onprogress != null && this.onprogress({loaded:loaded, total:total, progress:this.progress}); + this.onprogress && this.onprogress({loaded:loaded, total:total, progress:this.progress}); }; /** @@ -4123,9 +3887,8 @@ this.createjs = this.createjs || {}; p.handleAudioDecoded = function (decodedAudio) { this.progress = 1; this.result = decodedAudio; - this.src = this.originalSrc; this.owner.addPreloadResults(this.src, this.result); - this.onload && this.onload(); + this.onload && this.onload(this); }; /** @@ -4138,6 +3901,23 @@ this.createjs = this.createjs || {}; this.onerror && this.onerror(evt); }; + /** + * Remove all external references from loader + * #method cleanUp + */ + p.cleanUp = function () { + if(!this.request) {return;} + this.src = null; + this.owner = null; + this.request.onload = null; + this.request.onerror = null; + this.request.onprogress = null; + this.request = null; + this.onload = null; + this.onprogress = null; + this.onerror = null; + }; + p.toString = function () { return "[WebAudioPlugin Loader]"; }; @@ -4197,12 +3977,13 @@ this.createjs = this.createjs || {}; * tags are precreated to allow Chrome to load them. Please use {{#crossLink "Sound.MAX_INSTANCES"}}{{/crossLink}} as * a guide to how many total audio tags you can safely use in all browsers. * - * IE 9 html limitations
    + * IE html limitations
    *
    • There is a delay in applying volume changes to tags that occurs once playback is started. So if you have * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of * when or how you apply the volume change, as the tag seems to need to play to apply it.
    • *
    • MP3 encoding will not always work for audio tags if it's not default. We've found default encoding with * 64kbps works.
    • + *
    • Occasionally very short samples will get cut off.
    • *
    • There is a limit to how many audio tags you can load and play at once, which appears to be determined by * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate.
    * @@ -4325,14 +4106,9 @@ this.createjs = this.createjs || {}; * @static */ s.isSupported = function () { - if (createjs.Sound.BrowserDetect.isIOS && !s.enableIOS) { - return false; - } + if (createjs.Sound.BrowserDetect.isIOS && !s.enableIOS) {return false;} s._generateCapabilities(); - var t = s.tag; // OJR do we still need this check, when cap will already be null if this is the case - if (t == null || s._capabilities == null) { - return false; - } + if (s._capabilities == null) {return false;} return true; }; @@ -4344,13 +4120,9 @@ this.createjs = this.createjs || {}; * @protected */ s._generateCapabilities = function () { - if (s._capabilities != null) { - return; - } - var t = s.tag = document.createElement("audio"); - if (t.canPlayType == null) { - return null; - } + if (s._capabilities != null) {return;} + var t = document.createElement("audio"); + if (t.canPlayType == null) {return null;} s._capabilities = { panning:true, @@ -4383,7 +4155,7 @@ this.createjs = this.createjs || {}; p._audioSources = null; /** - * The default number of instances to allow. Passed back to {{#crossLink "Sound"}}{{/crossLink}} when a source + * The default number of instances to allow. Used by {{#crossLink "Sound"}}{{/crossLink}} when a source * is registered using the {{#crossLink "Sound/register"}}{{/crossLink}} method. This is only used if * a value is not provided. * @@ -4395,9 +4167,6 @@ this.createjs = this.createjs || {}; */ p.defaultNumChannels = 2; - // Proxies, make removing listeners easier. - p.loadedHandler = null; - /** * An initialization function run by the constructor * @method _init @@ -4422,52 +4191,17 @@ this.createjs = this.createjs || {}; this._audioSources[src] = true; // Note this does not mean preloading has started var channel = createjs.HTMLAudioPlugin.TagPool.get(src); var tag = null; - var l = instances || this.defaultNumChannels; - for (var i = 0; i < l; i++) { // OJR should we be enforcing s.MAX_INSTANCES here? Does the chrome bug still exist, or can we change this code? + var l = instances; + for (var i = 0; i < l; i++) { tag = this._createTag(src); channel.add(tag); } - tag.id = src; // co-opting id as we need a way to store original src in case it is changed before loading - this.loadedHandler = createjs.proxy(this._handleTagLoad, this); // we need this bind to be able to remove event listeners - tag.addEventListener && tag.addEventListener("canplaythrough", this.loadedHandler); - if(tag.onreadystatechange == null) { - tag.onreadystatechange = this.loadedHandler; - } else { - var f = tag.onreadystatechange; - // OJR will this lose scope? - tag.onreadystatechange = function() { - f(); - this.loadedHandler(); - } - } - return { - tag:tag, // Return one instance for preloading purposes - numChannels:l // The default number of channels to make for this Sound or the passed in value + tag:tag // Return one instance for preloading purposes }; }; - // TODO remove this when | approach is removed - /** - * Deprecated as this will not be required with new approach to basePath. - * Checks if src was changed on tag used to create instances in TagPool before loading - * Currently PreloadJS does this when a basePath is set, so we are replicating that behavior for internal preloading. - * @method _handleTagLoad - * @param event - * @protected - * @deprecated - */ - p._handleTagLoad = function(event) { - // cleanup and so we don't send the event more than once - event.target.removeEventListener && event.target.removeEventListener("canplaythrough", this.loadedHandler); - event.target.onreadystatechange = null; - - if (event.target.src == event.target.id) { return; } - // else src has changed before loading, and we need to make the change to TagPool because we pre create tags - createjs.HTMLAudioPlugin.TagPool.checkSrc(event.target.id); - }; - /** * Create an HTML audio tag. * @method _createTag @@ -4503,7 +4237,7 @@ this.createjs = this.createjs || {}; * @since 0.4.1 */ p.removeAllSounds = function () { - this._audioSources = {}; // this drops all references, in theory freeing them for garbage collection + this._audioSources = {}; createjs.HTMLAudioPlugin.TagPool.removeAll(); }; @@ -4541,12 +4275,12 @@ this.createjs = this.createjs || {}; * Internally preload a sound. * @method preload * @param {String} src The sound URI to load. - * @param {Object} instance An object containing a tag property that is an HTML audio tag used to load src. + * @param {Object} tag An HTML audio tag used to load src. * @since 0.4.0 */ - p.preload = function (src, instance) { + p.preload = function (src, tag) { this._audioSources[src] = true; - new createjs.HTMLAudioPlugin.Loader(src, instance.tag); + new createjs.HTMLAudioPlugin.Loader(src, tag); }; p.toString = function () { @@ -4575,10 +4309,8 @@ this.createjs = this.createjs || {}; p._owner = null; p.loaded = false; p._offset = 0; - p._delay = 0; p._volume = 1; - // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors - try { + if (createjs.definePropertySupported) { Object.defineProperty(p, "volume", { get: function() { return this._volume; @@ -4590,9 +4322,7 @@ this.createjs = this.createjs || {}; this._updateVolume(); } }); - } catch (e) { - // dispatch message or error? - }; + } p.pan = 0; p._duration = 0; p._remainingLoops = 0; @@ -4613,6 +4343,8 @@ this.createjs = this.createjs || {}; this.src = src; this._owner = owner; + this._duration = createjs.HTMLAudioPlugin.TagPool.getDuration(this.src); + this._endedHandler = createjs.proxy(this._handleSoundComplete, this); this._readyHandler = createjs.proxy(this._handleSoundReady, this); this._stalledHandler = createjs.proxy(this._handleSoundStalled, this); @@ -4640,16 +4372,11 @@ this.createjs = this.createjs || {}; } clearTimeout(this._delayTimeoutId); - if (window.createjs == null) { - return; - } createjs.Sound._playFinished(this); }; p._interrupt = function () { - if (this.tag == null) { - return; - } + if (this.tag == null) {return;} this.playState = createjs.Sound.PLAY_INTERRUPTED; this._cleanUp(); this.paused = this._paused = false; @@ -4658,14 +4385,11 @@ this.createjs = this.createjs || {}; // Public API p.play = function (interrupt, delay, offset, loop, volume, pan) { - this._cleanUp(); //LM: Is this redundant? + this._cleanUp(); createjs.Sound._playInstance(this, interrupt, delay, offset, loop, volume, pan); }; p._beginPlaying = function (offset, loop, volume, pan) { - if (window.createjs == null) { - return -1; - } var tag = this.tag = createjs.HTMLAudioPlugin.TagPool.getInstance(this.src); if (tag == null) { this.playFailed(); @@ -4677,8 +4401,7 @@ this.createjs = this.createjs || {}; // Reset this instance. this._offset = offset; this.volume = volume; - this.pan = pan; // not pan has no effect - this._updateVolume(); // note this will set for mute and _masterMute + this._updateVolume(); this._remainingLoops = loop; if (tag.readyState !== 4) { @@ -4697,24 +4420,17 @@ this.createjs = this.createjs || {}; // Note: Sounds stall when trying to begin playback of a new audio instance when the existing instances // has not loaded yet. This doesn't mean the sound will not play. p._handleSoundStalled = function (event) { - this._cleanUp(); // OJR NOTE this will stop playback, and I think we should remove this and let the developer decide how to handle stalled instances + this._cleanUp(); // OJR this will stop playback, we could remove this and let the developer decide how to handle stalled instances this._sendEvent("failed"); }; p._handleSoundReady = function (event) { - if (window.createjs == null) { - return; - } - - // OJR would like a cleaner way to do this in _init, discuss with LM - this._duration = this.tag.duration * 1000; // need this for setPosition on stopped sounds - this.playState = createjs.Sound.PLAY_SUCCEEDED; this.paused = this._paused = false; this.tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false); if (this._offset >= this.getDuration()) { - this.playFailed(); // OJR: throw error? + this.playFailed(); return; } else if (this._offset > 0) { this.tag.currentTime = this._offset * 0.001; @@ -4732,20 +4448,15 @@ this.createjs = this.createjs || {}; p.pause = function () { if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED && this.tag != null) { this.paused = this._paused = true; - // Note: when paused by user, we hold a reference to our tag. We do not release it until stopped. this.tag.pause(); - clearTimeout(this._delayTimeoutId); - return true; } return false; }; p.resume = function () { - if (!this._paused || this.tag == null) { - return false; - } + if (!this._paused || this.tag == null) {return false;} this.paused = this._paused = false; this.tag.play(); return true; @@ -4761,7 +4472,6 @@ this.createjs = this.createjs || {}; p.setMasterVolume = function (value) { this._updateVolume(); - return true; }; p.setVolume = function (value) { @@ -4772,12 +4482,7 @@ this.createjs = this.createjs || {}; p._updateVolume = function () { if (this.tag != null) { var newVolume = (this._muted || createjs.Sound._masterMute) ? 0 : this._volume * createjs.Sound._masterVolume; - if (newVolume != this.tag.volume) { - this.tag.volume = newVolume; - } - return true; - } else { - return false; + if (newVolume != this.tag.volume) {this.tag.volume = newVolume;} } }; @@ -4787,14 +4492,10 @@ this.createjs = this.createjs || {}; p.setMasterMute = function (isMuted) { this._updateVolume(); - return true; }; p.setMute = function (isMuted) { - if (isMuted == null || isMuted == undefined) { - return false; - } - + if (isMuted == null) {return false;} this._muted = isMuted; this._updateVolume(); return true; @@ -4804,7 +4505,7 @@ this.createjs = this.createjs || {}; return this._muted; }; - // Can not set pan in HTML + // Can not set pan in HTML audio p.setPan = function (value) { return false; }; @@ -4814,9 +4515,7 @@ this.createjs = this.createjs || {}; }; p.getPosition = function () { - if (this.tag == null) { - return this._offset; - } + if (this.tag == null) {return this._offset;} return this.tag.currentTime * 1000; }; @@ -4841,21 +4540,15 @@ this.createjs = this.createjs || {}; p._handleSoundComplete = function (event) { this._offset = 0; - - if (window.createjs == null) { - return; - } this.playState = createjs.Sound.PLAY_FINISHED; this._cleanUp(); this._sendEvent("complete"); }; - // handles looping functionality // NOTE with this approach audio will loop as reliably as the browser allows // but we could end up sending the loop event after next loop playback begins p.handleSoundLoop = function (event) { this._offset = 0; - this._remainingLoops--; if(this._remainingLoops == 0) { this.tag.loop = false; @@ -4865,9 +4558,6 @@ this.createjs = this.createjs || {}; }; p.playFailed = function () { - if (window.createjs == null) { - return; - } this.playState = createjs.Sound.PLAY_FAILED; this._cleanUp(); this._sendEvent("failed"); @@ -4946,12 +4636,12 @@ this.createjs = this.createjs || {}; this.loadedHandler = createjs.proxy(this.sendLoadedEvent, this); // we need this bind to be able to remove event listeners this.tag.addEventListener && this.tag.addEventListener("canplaythrough", this.loadedHandler); if(this.tag.onreadystatechange == null) { - this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); // OJR not 100% sure we need this, just copied from PreloadJS + this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); } else { var f = this.tag.onreadystatechange; this.tag.onreadystatechange = function() { f(); - this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); // OJR not 100% sure we need this, just copied from PreloadJS + this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); } } @@ -4994,6 +4684,7 @@ this.createjs = this.createjs || {}; this.tag.removeEventListener && this.tag.removeEventListener("canplaythrough", this.loadedHandler); // cleanup and so we don't send the event more than once this.tag.onreadystatechange = null; // cleanup and so we don't send the event more than once createjs.Sound._sendFileLoadEvent(this.src); // fire event or callback on Sound + }; // used for debugging @@ -5056,9 +4747,7 @@ this.createjs = this.createjs || {}; */ s.remove = function (src) { var channel = s.tags[src]; - if (channel == null) { - return false; - } + if (channel == null) {return false;} channel.removeAll(); delete(s.tags[src]); return true; @@ -5085,9 +4774,7 @@ this.createjs = this.createjs || {}; */ s.getInstance = function (src) { var channel = s.tags[src]; - if (channel == null) { - return null; - } + if (channel == null) {return null;} return channel.get(); }; @@ -5101,27 +4788,20 @@ this.createjs = this.createjs || {}; */ s.setInstance = function (src, tag) { var channel = s.tags[src]; - if (channel == null) { - return null; - } + if (channel == null) {return null;} return channel.set(tag); }; /** - * A function to check if src has changed in the loaded audio tag. - * This is required because PreloadJS appends a basePath to the src before loading. - * Note this is currently only called when a change is detected - * #method checkSrc - * @param src the unaltered src that is used to store the channel. - * @static - * @protected + * Gets the duration of the src audio in milliseconds + * #method getDuration + * @param {String} src The source file used by the audio tag. + * @return {Number} Duration of src in milliseconds */ - s.checkSrc = function (src) { + s.getDuration= function (src) { var channel = s.tags[src]; - if (channel == null) { - return null; - } - channel.checkSrcChange(); + if (channel == null) {return 0;} + return channel.getDuration(); }; var p = TagPool.prototype; @@ -5161,6 +4841,15 @@ this.createjs = this.createjs || {}; */ p.tags = null; + /** + * The duration property of all audio tags, converted to milliseconds, which originally is only available on the + * last tag in the tags array because that is the one that is loaded. + * #property + * @type {Number} + * @protected + */ + p.duration = 0; + // constructor p._init = function (src) { this.src = src; @@ -5197,14 +4886,10 @@ this.createjs = this.createjs || {}; * @return {HTMLAudioElement} An HTML audio tag. */ p.get = function () { - if (this.tags.length == 0) { - return null; - } + if (this.tags.length == 0) {return null;} this.available = this.tags.length; var tag = this.tags.pop(); - if (tag.parentNode == null) { - document.body.appendChild(tag); - } + if (tag.parentNode == null) {document.body.appendChild(tag);} return tag; }; @@ -5215,26 +4900,19 @@ this.createjs = this.createjs || {}; */ p.set = function (tag) { var index = createjs.indexOf(this.tags, tag); - if (index == -1) { - this.tags.push(tag); - } + if (index == -1) {this.tags.push(tag);} this.available = this.tags.length; }; /** - * Make sure the src of all other tags is correct after load. - * This is needed because PreloadJS appends a basePath to src before loading. - * #method checkSrcChange + * Gets the duration for the src audio and on first call stores it to this.duration + * #method getDuration + * @return {Number} Duration of the src in milliseconds */ - p.checkSrcChange = function () { - // the last tag always has the latest src after loading - //var i = this.length-1; // this breaks in Firefox because it is not correctly removing an event listener - var i = this.tags.length - 1; - if(i == -1) return; // CodeCombat addition; sometimes errors in IE without this... - var newSrc = this.tags[i].src; - while(i--) { - this.tags[i].src = newSrc; - } + p.getDuration = function () { + // this will work because this will be only be run the first time a sound instance is created and before any tags are taken from the pool + if (!this.duration) {this.duration = this.tags[this.tags.length - 1].duration * 1000;} + return this.duration; }; p.toString = function () { From 29e7b8e5c1dff7ff899ff0a02063708cd669c421 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sat, 22 Mar 2014 09:48:36 -0700 Subject: [PATCH 09/30] Fixed mail to correctly capture the matches. --- app/views/play/ladder/ladder_tab.coffee | 13 ++++++----- app/views/play/spectate_view.coffee | 2 +- server/routes/mail.coffee | 30 +++++++++++++++---------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/app/views/play/ladder/ladder_tab.coffee b/app/views/play/ladder/ladder_tab.coffee index 7b15e4c94..81450f723 100644 --- a/app/views/play/ladder/ladder_tab.coffee +++ b/app/views/play/ladder/ladder_tab.coffee @@ -19,10 +19,10 @@ module.exports = class LadderTabView extends CocoView id: 'ladder-tab-view' template: require 'templates/play/ladder/ladder_tab' startsLoading: true - + events: 'click .connect-facebook': 'onConnectFacebook' - + subscriptions: 'facebook-logged-in': 'onConnectedWithFacebook' @@ -32,11 +32,11 @@ module.exports = class LadderTabView extends CocoView @leaderboards = {} @refreshLadder() @checkFriends() - + onConnectFacebook: -> @connecting = true FB.login() - + onConnectedWithFacebook: -> location.reload() if @connecting @@ -61,7 +61,7 @@ module.exports = class LadderTabView extends CocoView method: 'POST' success: @facebookFriendsLoaded } - + facebookFriendsLoaded: (result) => friendsMap = {} friendsMap[friend.id] = friend.name for friend in @facebookData @@ -83,9 +83,10 @@ module.exports = class LadderTabView extends CocoView $.when(promises...).then(@leaderboardsLoaded) leaderboardsLoaded: => + return if @destroyed @loadingLeaderboards = false @renderMaybe() - + renderMaybe: -> return if @loadingFriends or @loadingLeaderboards @startsLoading = false diff --git a/app/views/play/spectate_view.coffee b/app/views/play/spectate_view.coffee index 283c7dc57..97653ff78 100644 --- a/app/views/play/spectate_view.coffee +++ b/app/views/play/spectate_view.coffee @@ -107,7 +107,7 @@ module.exports = class SpectateLevelView extends View team: @getQueryVariable("team") @levelLoader.once 'loaded-all', @onLevelLoaderLoaded, @ @levelLoader.on 'progress', @onLevelLoaderProgressChanged, @ - @god = new God() + @god = new God maxWorkerPoolSize: 1, maxAngels: 1 getRenderData: -> c = super() diff --git a/server/routes/mail.coffee b/server/routes/mail.coffee index 9fb277698..6527e4a26 100644 --- a/server/routes/mail.coffee +++ b/server/routes/mail.coffee @@ -31,6 +31,11 @@ getAllLadderScores = (next) -> # Query to get sessions to make histogram # db.level.sessions.find({"submitted":true,"levelID":"brawlwood",team:"ogres"},{"_id":0,"totalScore":1}) +DEBUGGING = false +LADDER_PREGAME_INTERVAL = 2 * 3600 * 1000 # Send emails two hours before players last submitted. +getTimeFromDaysAgo = (now, daysAgo) -> + t = now - 86400 * 1000 * daysAgo - LADDER_PREGAME_INTERVAL + isRequestFromDesignatedCronHandler = (req, res) -> if req.ip isnt config.mail.cronHandlerPublicIP and req.ip isnt config.mail.cronHandlerPrivateIP console.log "RECEIVED REQUEST FROM IP #{req.ip}(headers indicate #{req.headers['x-forwarded-for']}" @@ -40,25 +45,22 @@ isRequestFromDesignatedCronHandler = (req, res) -> return false return true - handleLadderUpdate = (req, res) -> log.info("Going to see about sending ladder update emails.") requestIsFromDesignatedCronHandler = isRequestFromDesignatedCronHandler req, res - #unless requestIsFromDesignatedCronHandler then return + return unless requestIsFromDesignatedCronHandler or DEBUGGING res.send('Great work, Captain Cron! I can take it from here.') res.end() # TODO: somehow fetch the histograms emailDays = [1, 2, 4, 7, 30] now = new Date() - getTimeFromDaysAgo = (daysAgo) -> - # 2 hours before the date - t = now - (86400 * daysAgo + 2 * 3600) * 1000 for daysAgo in emailDays # Get every session that was submitted in a 5-minute window after the time. - startTime = getTimeFromDaysAgo daysAgo + startTime = getTimeFromDaysAgo now, daysAgo endTime = startTime + 5 * 60 * 1000 - #endTime = startTime + 1.5 * 60 * 60 * 1000 # Debugging: make sure there's something to send + if DEBUGGING + 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" @@ -71,9 +73,9 @@ handleLadderUpdate = (req, res) -> log.error "Couldn't fetch ladder updates for #{findParameters}\nError: #{err}" return errors.serverError res, "Ladder update email query failed: #{JSON.stringify(err)}" log.info "Found #{results.length} ladder sessions to email updates about for #{daysAgo} day(s) ago." - sendLadderUpdateEmail result, daysAgo for result in results + sendLadderUpdateEmail result, now, daysAgo for result in results -sendLadderUpdateEmail = (session, daysAgo) -> +sendLadderUpdateEmail = (session, now, daysAgo) -> User.findOne({_id: session.creator}).select("name email firstName lastName emailSubscriptions preferredLanguage").lean().exec (err, user) -> if err log.error "Couldn't find user for #{session.creator} from session #{session._id}" @@ -89,19 +91,23 @@ sendLadderUpdateEmail = (session, daysAgo) -> # Fetch the most recent defeat and victory, if there are any. # (We could look at strongest/weakest, but we'd have to fetch everyone, or denormalize more.) - matches = _.filter session.matches, (match) -> match.date >= (new Date() - 86400 * 1000 * daysAgo) + matches = _.filter session.matches, (match) -> match.date >= getTimeFromDaysAgo now, daysAgo defeats = _.filter matches, (match) -> match.metrics.rank is 1 and match.opponents[0].metrics.rank is 0 victories = _.filter matches, (match) -> match.metrics.rank is 0 and match.opponents[0].metrics.rank is 1 + #ties = _.filter matches, (match) -> match.metrics.rank is 0 and match.opponents[0].metrics.rank is 0 defeat = _.last defeats victory = _.last victories + #log.info "#{user.name} had #{matches.length} matches from last #{daysAgo} days out of #{session.matches.length} total matches. #{defeats.length} defeats, #{victories.length} victories, and #{ties.length} ties." + #matchInfos = ("\t#{match.date}\t#{match.date >= getTimeFromDaysAgo(now, daysAgo)}\t#{match.metrics.rank}\t#{match.opponents[0].metrics.rank}" for match in session.matches) + #log.info "Matches:\n#{matchInfos.join('\n')}" + sendEmail = (defeatContext, victoryContext) -> # TODO: do something with the preferredLanguage? context = email_id: sendwithus.templates.ladder_update_email recipient: - address: user.email - #address: 'nick@codecombat.com' # Debugging + address: if DEBUGGING then 'nick@codecombat.com' else user.email name: name email_data: name: name From baf8adcc7479116d3e548945464dda49e4335802 Mon Sep 17 00:00:00 2001 From: Mikhail Koltsov Date: Sat, 22 Mar 2014 20:50:50 +0400 Subject: [PATCH 10/30] added nothing --- app/templates/editor/level/table.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/editor/level/table.jade b/app/templates/editor/level/table.jade index 37decec4d..594d09ea4 100755 --- a/app/templates/editor/level/table.jade +++ b/app/templates/editor/level/table.jade @@ -10,7 +10,7 @@ table.table th(data-i18n="general.name") Name th(data-i18n="general.description") Description th(data-i18n="general.version") Version - + for data in documents - data = data.attributes; tr @@ -18,4 +18,4 @@ table.table a(href="/editor/level/#{data.slug || data._id}") | #{data.name} td.body-row #{data.description} - td #{data.version.major}.#{data.version.minor} \ No newline at end of file + td #{data.version.major}.#{data.version.minor} From 1224fa8d9183eae8d68bac387b6a85b63e910f12 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 22 Mar 2014 10:12:02 -0700 Subject: [PATCH 11/30] Reverted soundjs, because the latest version is different/buggy. --- vendor/scripts/soundjs-NEXT.combined.js | 1018 +++++++++++++++-------- 1 file changed, 670 insertions(+), 348 deletions(-) diff --git a/vendor/scripts/soundjs-NEXT.combined.js b/vendor/scripts/soundjs-NEXT.combined.js index aa7766574..09e8920c7 100644 --- a/vendor/scripts/soundjs-NEXT.combined.js +++ b/vendor/scripts/soundjs-NEXT.combined.js @@ -856,72 +856,6 @@ this.createjs = this.createjs||{}; }; } -}());/* -* defineProperty -* Visit http://createjs.com/ for documentation, updates and examples. -* -* Copyright (c) 2010 gskinner.com, inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -*/ - -/** - * @module CreateJS - */ - -// namespace: -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ -(function() { - "use strict"; - - /** - * Boolean value indicating if Object.defineProperty is supported. - * - * @property definePropertySupported - * @type {Boolean} - * @default true - */ - var t = Object.defineProperty ? true : false; - - // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors - var foo = {}; - try { - Object.defineProperty(foo, "bar", { - get: function() { - return this._bar; - }, - set: function(value) { - this._bar = value; - } - }); - } catch (e) { - t = false; - }; - - createjs.definePropertySupported = t; }());/* * Sound * Visit http://createjs.com/ for documentation, updates and examples. @@ -986,8 +920,8 @@ this.createjs = this.createjs || {}; * } * *

    Browser Support

    - * Audio will work in browsers which support WebAudio (http://caniuse.com/audio-api) - * or HTMLAudioElement (http://caniuse.com/audio). A Flash fallback can be added + * Audio will work in browsers which support HTMLAudioElement (http://caniuse.com/audio) + * or WebAudio (http://caniuse.com/audio-api). A Flash fallback can be added * as well, which will work in any browser that supports the Flash player. * @module SoundJS * @main SoundJS @@ -997,6 +931,11 @@ this.createjs = this.createjs || {}; "use strict"; + //TODO: Interface to validate plugins and throw warnings + //TODO: Determine if methods exist on a plugin before calling // OJR this is only an issue if something breaks or user changes something + //TODO: Interface to validate instances and throw warnings + //TODO: Surface errors on audio from all plugins + //TODO: Timeouts // OJR for? /** * The Sound class is the public API for creating sounds, controlling the overall sound levels, and managing plugins. * All Sound APIs on this class are static. @@ -1006,7 +945,7 @@ this.createjs = this.createjs || {}; * or register multiple sounds using {{#crossLink "Sound/registerManifest"}}{{/crossLink}}. If you don't register a * sound prior to attempting to play it using {{#crossLink "Sound/play"}}{{/crossLink}} or create it using {{#crossLink "Sound/createInstance"}}{{/crossLink}}, * the sound source will be automatically registered but playback will fail as the source will not be ready. If you use - * PreloadJS, registration is handled for you when the sound is + * PreloadJS, this is handled for you when the sound is * preloaded. It is recommended to preload sounds either internally using the register functions or externally using * PreloadJS so they are ready when you want to use them. * @@ -1043,12 +982,11 @@ this.createjs = this.createjs || {}; * * Sound can be used as a plugin with PreloadJS to help preload audio properly. Audio preloaded with PreloadJS is * automatically registered with the Sound class. When audio is not preloaded, Sound will do an automatic internal - * load. As a result, it may fail to play the first time play is called if the audio is not finished loading. Use the + * load. As a result, it may not play immediately the first time play is called. Use the * {{#crossLink "Sound/fileload"}}{{/crossLink}} event to determine when a sound has finished internally preloading. * It is recommended that all audio is preloaded before it is played. * - * var queue = new createjs.LoadQueue(); - * queue.installPlugin(createjs.Sound); + * createjs.PreloadJS.installPlugin(createjs.Sound); * * Mobile Safe Approach
    * Mobile devices require sounds to be played inside of a user initiated event (touch/click) in varying degrees. @@ -1071,7 +1009,6 @@ this.createjs = this.createjs || {}; * when or how you apply the volume change, as the tag seems to need to play to apply it. *
  • MP3 encoding will not always work for audio tags, particularly in Internet Explorer. We've found default * encoding with 64kbps works.
  • - *
  • Occasionally very short samples will get cut off.
  • *
  • There is a limit to how many audio tags you can load and play at once, which appears to be determined by * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate.
  • * @@ -1107,16 +1044,19 @@ this.createjs = this.createjs || {}; var s = Sound; - // TODO DEPRECATED /** - * REMOVED - * Use {{#crossLink "Sound/alternateExtensions:property"}}{{/crossLink}} instead + * DEPRECATED + * This approach has is being replaced by {{#crossLink "Sound/alternateExtensions:property"}}{{/crossLink}}, and + * support will be removed in the next version. + * + * The character (or characters) that are used to split multiple paths from an audio source. * @property DELIMITER * @type {String} * @default | * @static * @deprecated */ + s.DELIMITER = "|"; /** * The interrupt value to interrupt any currently playing instance with the same source, if the maximum number of @@ -1219,7 +1159,7 @@ this.createjs = this.createjs || {}; * @default ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"] * @since 0.4.0 */ - s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]; + s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]; // OJR FlashPlugin does not currently support /** * Some extensions use another type of extension support to play (one of them is a codex). This allows you to map @@ -1406,6 +1346,16 @@ this.createjs = this.createjs || {}; * @since 0.4.1 */ + //TODO: Deprecated + /** + * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "Sound/fileload:event"}}{{/crossLink}} + * event. + * @property onLoadComplete + * @type {Function} + * @deprecated Use addEventListener and the fileload event. + * @since 0.4.0 + */ + /** * Used by external plugins to dispatch file load events. * @method _sendFileLoadEvent @@ -1456,7 +1406,33 @@ this.createjs = this.createjs || {}; }; /** - * Used by {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} to register a Sound plugin. + * Deprecated in favor of {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} with a single argument. + * createjs.Sound.registerPlugins([createjs.WebAudioPlugin]); + * + * @method registerPlugin + * @param {Object} plugin The plugin class to install. + * @return {Boolean} Whether the plugin was successfully initialized. + * @static + * @deprecated + */ + s.registerPlugin = function (plugin) { + try { + console.log("createjs.Sound.registerPlugin has been deprecated. Please use registerPlugins."); + } catch (err) { + // you are in IE with the console closed, you monster + } + return s._registerPlugin(plugin); + }; + + /** + * Register a Sound plugin. Plugins handle the actual playback of audio. The default plugins are + * ({{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}), + * and are installed if no other plugins are present when the user attempts to start playback or register sound. + *

    Example

    + * createjs.FlashPlugin.swfPath = "../src/SoundJS/"; + * createjs.Sound._registerPlugin(createjs.FlashPlugin); + * + * To register multiple plugins, use {{#crossLink "Sound/registerPlugins"}}{{/crossLink}}. * * @method _registerPlugin * @param {Object} plugin The plugin class to install. @@ -1465,9 +1441,14 @@ this.createjs = this.createjs || {}; * @private */ s._registerPlugin = function (plugin) { + s._pluginsRegistered = true; + if (plugin == null) { + return false; + } // Note: Each plugin is passed in as a class reference, but we store the activePlugin as an instance if (plugin.isSupported()) { s.activePlugin = new plugin(); + //TODO: Check error on initialization return true; } return false; @@ -1486,9 +1467,9 @@ this.createjs = this.createjs || {}; * @static */ s.registerPlugins = function (plugins) { - s._pluginsRegistered = true; for (var i = 0, l = plugins.length; i < l; i++) { - if (s._registerPlugin(plugins[i])) { + var plugin = plugins[i]; + if (s._registerPlugin(plugin)) { return true; } } @@ -1508,9 +1489,15 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.initializeDefaultPlugins = function () { - if (s.activePlugin != null) {return true;} - if (s._pluginsRegistered) {return false;} - if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) {return true;} + if (s.activePlugin != null) { + return true; + } + if (s._pluginsRegistered) { + return false; + } + if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) { + return true; + } return false; }; @@ -1557,7 +1544,9 @@ this.createjs = this.createjs || {}; * @static */ s.getCapabilities = function () { - if (s.activePlugin == null) {return null;} + if (s.activePlugin == null) { + return null; + } return s.activePlugin._capabilities; }; @@ -1575,7 +1564,9 @@ this.createjs = this.createjs || {}; * @see getCapabilities */ s.getCapability = function (key) { - if (s.activePlugin == null) {return null;} + if (s.activePlugin == null) { + return null; + } return s.activePlugin._capabilities[key]; }; @@ -1590,64 +1581,19 @@ this.createjs = this.createjs || {}; * @param {Number|String|Boolean|Object} [data] Data associated with the item. Sound uses the data parameter as the * number of channels for an audio instance, however a "channels" property can be appended to the data object if * this property is used for other information. The audio channels will default to 1 if no value is found. + * @param {String} [path] A combined basepath and subPath from PreloadJS that has already been prepended to src. * @return {Boolean|Object} An object with the modified values of those that were passed in, or false if the active * plugin can not play the audio type. * @protected * @static */ - s.initLoad = function (src, type, id, data) { - return s._registerSound(src, id, data); - }; - - /** - * Internal method for loading sounds. This should not be called directly. - * - * @method _registerSound - * @param {String | Object} src The source to load. - * @param {String} [id] An id specified by the user to play the sound later. - * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of - * channels for an audio instance, however a "channels" property can be appended to the data object if it is used - * for other information. The audio channels will set a default based on plugin if no value is found. - * @return {Object} An object with the modified values that were passed in, which defines the sound. - * Returns false if the source cannot be parsed or no plugins can be initialized. - * Returns true if the source is already loaded. - * @static - * @private - * @since 0.5.3 - */ - - s._registerSound = function (src, id, data) { - if (!s.initializeDefaultPlugins()) {return false;} - - var details = s._parsePath(src, "sound", id, data); - if (details == null) {return false;} - - if (id != null) {s._idHash[id] = details.src;} - - var numChannels = s.activePlugin.defaultNumChannels || null; - if (data != null) { - if (!isNaN(data.channels)) { - numChannels = parseInt(data.channels); - } - else if (!isNaN(data)) { - numChannels = parseInt(data); - } + s.initLoad = function (src, type, id, data, path) { + // remove path from src so we can continue to support "|" splitting of src files // TODO remove this when "|" is removed + src = src.replace(path, ""); + var details = s.registerSound(src, id, data, false, path); + if (details == null) { + return false; } - var loader = s.activePlugin.register(details.src, numChannels); // Note only HTML audio uses numChannels - - SoundChannel.create(details.src, numChannels); - - // return the number of instances to the user. This will also be returned in the load event. - if (data == null || !isNaN(data)) { - details.data = numChannels || SoundChannel.maxPerChannel(); - } else { - details.data.channels = numChannels || SoundChannel.maxPerChannel(); - } - - details.tag = loader.tag; - if (loader.completeHandler) {details.completeHandler = loader.completeHandler;} - if (loader.type) {details.type = loader.type;} - return details; }; @@ -1667,6 +1613,8 @@ this.createjs = this.createjs || {}; * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of * channels for an audio instance, however a "channels" property can be appended to the data object if it is used * for other information. The audio channels will set a default based on plugin if no value is found. + * @param {Boolean} [preload=true] If the sound should be internally preloaded so that it can be played back + * without an external preloader. This is currently used by PreloadJS when loading sounds to disable internal preloading. * @param {string} basePath Set a path that will be prepended to src for loading. * @return {Object} An object with the modified values that were passed in, which defines the sound. * Returns false if the source cannot be parsed or no plugins can be initialized. @@ -1674,27 +1622,90 @@ this.createjs = this.createjs || {}; * @static * @since 0.4.0 */ - s.registerSound = function (src, id, data, basePath) { + s.registerSound = function (src, id, data, preload, basePath) { + if (!s.initializeDefaultPlugins()) { + return false; + } + if (src instanceof Object) { - basePath = id; + basePath = id; //this assumes preload has not be passed in as a property // OJR check if arguments == 3 would be less fragile + //?? preload = src.preload; + // OJR refactor how data is passed in to make the parameters work better id = src.id; data = src.data; src = src.src; } - if (basePath != null) {src = basePath + src;} - - var details = s._registerSound(src, id, data); - - if(!details) {return false;} - - if (!s._preloadHash[details.src]) { s._preloadHash[details.src] = [];} - s._preloadHash[details.src].push({src:src, id:id, data:details.data}); - if (s._preloadHash[details.src].length == 1) { - // OJR note this will disallow reloading a sound if loading fails or the source changes - s.activePlugin.preload(details.src, details.tag); + // branch to different parse based on alternate formats setting + if (s.alternateExtensions.length) { + var details = s._parsePath2(src, "sound", id, data); } else { - if (s._preloadHash[details.src][0] == true) {return true;} + var details = s._parsePath(src, "sound", id, data); + } + if (details == null) { + return false; + } + if (basePath != null) { + src = basePath + src; + details.src = basePath + details.src; + } + + if (id != null) { + s._idHash[id] = details.src; + } + + var numChannels = null; // null tells SoundChannel to set this to it's internal maxDefault + if (data != null) { + if (!isNaN(data.channels)) { + numChannels = parseInt(data.channels); + } + else if (!isNaN(data)) { + numChannels = parseInt(data); + } + } + var loader = s.activePlugin.register(details.src, numChannels); // Note only HTML audio uses numChannels + + if (loader != null) { // all plugins currently return a loader + if (loader.numChannels != null) { + numChannels = loader.numChannels; + } // currently only HTMLAudio returns this + SoundChannel.create(details.src, numChannels); + + // return the number of instances to the user. This will also be returned in the load event. + if (data == null || !isNaN(data)) { + data = details.data = numChannels || SoundChannel.maxPerChannel(); + } else { + data.channels = details.data.channels = numChannels || SoundChannel.maxPerChannel(); + } + + // If the loader returns a tag, return it instead for preloading. + // OJR all loaders currently use tags? + if (loader.tag != null) { + details.tag = loader.tag; + } else if (loader.src) { + details.src = loader.src; + } + // If the loader returns a complete handler, pass it on to the prelaoder. + if (loader.completeHandler != null) { + details.completeHandler = loader.completeHandler; + } + if (loader.type) { + details.type = loader.type; + } + } + + if (preload != false) { + if (!s._preloadHash[details.src]) { + s._preloadHash[details.src] = []; + } // we do this so we can store multiple id's and data if needed + s._preloadHash[details.src].push({src:src, id:id, data:data}); // keep this data so we can return it in fileload event + if (s._preloadHash[details.src].length == 1) { + // if already loaded once, don't load a second time // OJR note this will disallow reloading a sound if loading fails or the source changes + s.activePlugin.preload(details.src, loader); + } else { + // if src already loaded successfully, return true + if (s._preloadHash[details.src][0] == true) {return true;} + } } return details; @@ -1730,8 +1741,8 @@ this.createjs = this.createjs || {}; s.registerManifest = function (manifest, basePath) { var returnValues = []; for (var i = 0, l = manifest.length; i < l; i++) { - returnValues[i] = createjs.Sound.registerSound(manifest[i].src, manifest[i].id, manifest[i].data, basePath); - } + returnValues[i] = createjs.Sound.registerSound(manifest[i].src, manifest[i].id, manifest[i].data, manifest[i].preload, basePath); + } // OJR consider removing .preload from args, as it is only used by PreloadJS return returnValues; }; @@ -1753,16 +1764,27 @@ this.createjs = this.createjs || {}; * @since 0.4.1 */ s.removeSound = function(src, basePath) { - if (s.activePlugin == null) {return false;} + if (s.activePlugin == null) { + return false; + } - if (src instanceof Object) {src = src.src;} + if (src instanceof Object) { + src = src.src; + } src = s._getSrcById(src); - if (basePath != null) {src = basePath + src;} - var details = s._parsePath(src); - if (details == null) {return false;} + if (s.alternateExtensions.length) { + var details = s._parsePath2(src); + } else { + var details = s._parsePath(src); + } + if (details == null) { + return false; + } + if (basePath != null) {details.src = basePath + details.src;} src = details.src; + // remove src from _idHash // Note "for in" can be a slow operation for(var prop in s._idHash){ if(s._idHash[prop] == src) { delete(s._idHash[prop]); @@ -1772,8 +1794,10 @@ this.createjs = this.createjs || {}; // clear from SoundChannel, which also stops and deletes all instances SoundChannel.removeSrc(src); + // remove src from _preloadHash delete(s._preloadHash[src]); + // activePlugin cleanup s.activePlugin.removeSound(src); return true; @@ -1826,7 +1850,7 @@ this.createjs = this.createjs || {}; s._idHash = {}; s._preloadHash = {}; SoundChannel.removeAll(); - if (s.activePlugin) {s.activePlugin.removeAllSounds();} + s.activePlugin.removeAllSounds(); }; /** @@ -1845,7 +1869,11 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.loadComplete = function (src) { - var details = s._parsePath(src, "sound"); + if (s.alternateExtensions.length) { + var details = s._parsePath2(src, "sound"); + } else { + var details = s._parsePath(src, "sound"); + } if (details) { src = s._getSrcById(details.src); } else { @@ -1855,8 +1883,10 @@ this.createjs = this.createjs || {}; }; /** - * Parse the path of a sound, usually from a manifest item. alternate extensions will be attempted in order if the - * current extension is not supported + * Parse the path of a sound, usually from a manifest item. Manifest items support single file paths, as well as + * composite paths using {{#crossLink "Sound/DELIMITER:property"}}{{/crossLink}}, which defaults to "|". The first path supported by the + * current browser/plugin will be used. + * NOTE the "|" approach is deprecated and will be removed in the next version * @method _parsePath * @param {String} value The path to an audio source. * @param {String} [type] The type of path. This will typically be "sound" or null. @@ -1868,22 +1898,60 @@ this.createjs = this.createjs || {}; * @protected */ s._parsePath = function (value, type, id, data) { + if (typeof(value) != "string") {value = value.toString();} + var sounds = value.split(s.DELIMITER); + if (sounds.length > 1) { + try { + console.log("createjs.Sound.DELIMITER \"|\" loading approach has been deprecated. Please use the new alternateExtensions property."); + } catch (err) { + // you are in IE with the console closed, you monster + } + } + var ret = {type:type || "sound", id:id, data:data}; + var c = s.getCapabilities(); + for (var i = 0, l = sounds.length; i < l; i++) { + var sound = sounds[i]; + + var match = sound.match(s.FILE_PATTERN); + if (match == null) { + return false; + } + var name = match[4]; + var ext = match[5]; + + if (c[ext] && createjs.indexOf(s.SUPPORTED_EXTENSIONS, ext) > -1) { + ret.name = name; + ret.src = sound; + ret.extension = ext; + return ret; + } + } + return null; + }; + + // new approach, when old approach is deprecated this will become _parsePath + s._parsePath2 = function (value, type, id, data) { if (typeof(value) != "string") {value = value.toString();} var match = value.match(s.FILE_PATTERN); - if (match == null) {return false;} - + if (match == null) { + return false; + } var name = match[4]; var ext = match[5]; + var c = s.getCapabilities(); var i = 0; while (!c[ext]) { ext = s.alternateExtensions[i++]; if (i > s.alternateExtensions.length) { return null;} // no extensions are supported } - value = value.replace("."+match[5], "."+ext); - var ret = {type:type || "sound", id:id, data:data, name:name, src:value, extension:ext}; + value = value.replace("."+match[5], "."+ext); + var ret = {type:type || "sound", id:id, data:data}; + ret.name = name; + ret.src = value; + ret.extension = ext; return ret; }; @@ -1928,8 +1996,11 @@ this.createjs = this.createjs || {}; */ s.play = function (src, interrupt, delay, offset, loop, volume, pan) { var instance = s.createInstance(src); + var ok = s._playInstance(instance, interrupt, delay, offset, loop, volume, pan); - if (!ok) {instance.playFailed();} + if (!ok) { + instance.playFailed(); + } return instance; }; @@ -1955,17 +2026,27 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.createInstance = function (src) { - if (!s.initializeDefaultPlugins()) {return s._defaultSoundInstance;} + if (!s.initializeDefaultPlugins()) { + return s._defaultSoundInstance; + } src = s._getSrcById(src); - var details = s._parsePath(src, "sound"); + if (s.alternateExtensions.length) { + var details = s._parsePath2(src, "sound"); + } else { + var details = s._parsePath(src, "sound"); + } var instance = null; if (details != null && details.src != null) { + // make sure that we have a sound channel (sound is registered or previously played) SoundChannel.create(details.src); instance = s.activePlugin.create(details.src); } else { + // the src is not supported, so give back a dummy instance. + // This can happen if PreloadJS fails because the plugin does not support the ext, and was passed an id which + // will not get added to the _idHash. instance = Sound._defaultSoundInstance; } @@ -1987,11 +2068,13 @@ this.createjs = this.createjs || {}; * @static */ s.setVolume = function (value) { - if (Number(value) == null) {return false;} + if (Number(value) == null) { + return false; + } value = Math.max(0, Math.min(1, value)); s._masterVolume = value; if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) { - var instances = this._instances; + var instances = this._instances; // OJR does this impact garbage collection more than it helps performance? for (var i = 0, l = instances.length; i < l; i++) { instances[i].setMasterVolume(value); } @@ -2013,6 +2096,14 @@ this.createjs = this.createjs || {}; return s._masterVolume; }; + /** + * REMOVED. Please see {{#crossLink "Sound/setMute"}}{{/crossLink}}. + * @method mute + * @param {Boolean} value Whether the audio should be muted or not. + * @static + * @deprecated This function has been deprecated. Please use setMute instead. + */ + /** * Mute/Unmute all audio. Note that muted audio still plays at 0 volume. This global mute value is maintained * separately and when set will override, but not change the mute property of individual instances. To mute an individual @@ -2028,7 +2119,9 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ s.setMute = function (value) { - if (value == null) {return false;} + if (value == null || value == undefined) { + return false; + } this._masterMute = value; if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) { @@ -2112,13 +2205,15 @@ this.createjs = this.createjs || {}; interrupt = interrupt || s.defaultInterruptBehavior; if (delay == null) {delay = 0;} if (offset == null) {offset = instance.getPosition();} - if (loop == null) {loop = 0;} // OJR consider using instance._remainingLoops + if (loop == null) {loop = 0;} if (volume == null) {volume = instance.volume;} if (pan == null) {pan = instance.pan;} if (delay == 0) { var ok = s._beginPlaying(instance, interrupt, offset, loop, volume, pan); - if (!ok) {return false;} + if (!ok) { + return false; + } } else { //Note that we can't pass arguments to proxy OR setTimeout (IE only), so just wrap the function call. // OJR WebAudio may want to handle this differently, so it might make sense to move this functionality into the plugins in the future @@ -2156,8 +2251,11 @@ this.createjs = this.createjs || {}; } var result = instance._beginPlaying(offset, loop, volume, pan); if (!result) { + //LM: Should we remove this from the SoundChannel (see finishedPlaying) var index = createjs.indexOf(this._instances, instance); - if (index > -1) {this._instances.splice(index, 1);} + if (index > -1) { + this._instances.splice(index, 1); + } return false; } return true; @@ -2168,12 +2266,15 @@ this.createjs = this.createjs || {}; * instead. * @method _getSrcById * @param {String} value The ID the sound was registered with. - * @return {String} The source of the sound if it has been registered with this ID or the value that was passed in. + * @return {String} The source of the sound. Returns null if src has been registered with this id. * @protected * @static */ s._getSrcById = function (value) { - return s._idHash[value] || value; + if (s._idHash == null || s._idHash[value] == null) { + return value; + } + return s._idHash[value]; }; /** @@ -2188,7 +2289,9 @@ this.createjs = this.createjs || {}; s._playFinished = function (instance) { SoundChannel.remove(instance); var index = createjs.indexOf(this._instances, instance); - if (index > -1) {this._instances.splice(index, 1);} // OJR this will always be > -1, there is no way for an instance to exist without being added to this._instances + if (index > -1) { + this._instances.splice(index, 1); + } }; createjs.Sound = Sound; @@ -2249,8 +2352,10 @@ this.createjs = this.createjs || {}; */ SoundChannel.removeSrc = function (src) { var channel = SoundChannel.get(src); - if (channel == null) {return false;} - channel._removeAll(); // this stops and removes all active instances + if (channel == null) { + return false; + } + channel.removeAll(); // this stops and removes all active instances delete(SoundChannel.channels[src]); return true; }; @@ -2261,7 +2366,7 @@ this.createjs = this.createjs || {}; */ SoundChannel.removeAll = function () { for(var channel in SoundChannel.channels) { - SoundChannel.channels[channel]._removeAll(); // this stops and removes all active instances + SoundChannel.channels[channel].removeAll(); // this stops and removes all active instances } SoundChannel.channels = {}; }; @@ -2276,8 +2381,10 @@ this.createjs = this.createjs || {}; */ SoundChannel.add = function (instance, interrupt) { var channel = SoundChannel.get(instance.src); - if (channel == null) {return false;} - return channel._add(instance, interrupt); + if (channel == null) { + return false; + } + return channel.add(instance, interrupt); }; /** * Remove an instance from the channel. @@ -2288,8 +2395,10 @@ this.createjs = this.createjs || {}; */ SoundChannel.remove = function (instance) { var channel = SoundChannel.get(instance.src); - if (channel == null) {return false;} - channel._remove(instance); + if (channel == null) { + return false; + } + channel.remove(instance); return true; }; /** @@ -2352,7 +2461,9 @@ this.createjs = this.createjs || {}; p.init = function (src, max) { this.src = src; this.max = max || this.maxDefault; - if (this.max == -1) {this.max = this.maxDefault;} + if (this.max == -1) { + this.max = this.maxDefault; + } this._instances = []; }; @@ -2362,7 +2473,7 @@ this.createjs = this.createjs || {}; * @param {Number} index The index to return. * @return {SoundInstance} The SoundInstance at a specific instance. */ - p._get = function (index) { + p.get = function (index) { return this._instances[index]; }; @@ -2372,8 +2483,10 @@ this.createjs = this.createjs || {}; * @param {SoundInstance} instance The instance to add. * @return {Boolean} The success of the method call. If the channel is full, it will return false. */ - p._add = function (instance, interrupt) { - if (!this._getSlot(interrupt, instance)) {return false;} + p.add = function (instance, interrupt) { + if (!this.getSlot(interrupt, instance)) { + return false; + } this._instances.push(instance); this.length++; return true; @@ -2386,9 +2499,11 @@ this.createjs = this.createjs || {}; * @return {Boolean} The success of the remove call. If the instance is not found in this channel, it will * return false. */ - p._remove = function (instance) { + p.remove = function (instance) { var index = createjs.indexOf(this._instances, instance); - if (index == -1) {return false;} + if (index == -1) { + return false; + } this._instances.splice(index, 1); this.length--; return true; @@ -2398,8 +2513,8 @@ this.createjs = this.createjs || {}; * Stop playback and remove all instances from the channel. Usually in response to a delete call. * #method removeAll */ - p._removeAll = function () { - // Note that stop() removes the item from the list + p.removeAll = function () { + // Note that stop() removes the item from the list, but we don't want to assume that. for (var i=this.length-1; i>=0; i--) { this._instances[i].stop(); } @@ -2413,11 +2528,11 @@ this.createjs = this.createjs || {}; * @return {Boolean} Determines if there is an available slot. Depending on the interrupt mode, if there are no slots, * an existing SoundInstance may be interrupted. If there are no slots, this method returns false. */ - p._getSlot = function (interrupt, instance) { + p.getSlot = function (interrupt, instance) { var target, replacement; for (var i = 0, l = this.max; i < l; i++) { - target = this._get(i); + target = this.get(i); // Available Space if (target == null) { @@ -2439,15 +2554,16 @@ this.createjs = this.createjs || {}; replacement = target; // Audio is a better candidate than the current target, according to playhead - } else if ( (interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) || - (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) { + } else if ( + (interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) || + (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) { replacement = target; } } if (replacement != null) { replacement._interrupt(); - this._remove(replacement); + this.remove(replacement); return true; } return false; @@ -2604,7 +2720,9 @@ this.createjs = this.createjs || {}; // OJR isMobile may be redundant with _isFileXHRSupported available. Consider removing. if (location.protocol == "file:" && !isMobilePhoneGap && !this._isFileXHRSupported()) { return false; } // Web Audio requires XHR, which is not usually available locally s._generateCapabilities(); - if (s.context == null) {return false;} + if (s.context == null) { + return false; + } return true; }; @@ -2649,19 +2767,28 @@ this.createjs = this.createjs || {}; * @protected */ s._generateCapabilities = function () { - if (s._capabilities != null) {return;} - // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section + if (s._capabilities != null) { + return; + } + // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section, + // therefore tag is still required for the capabilities check var t = document.createElement("audio"); - if (t.canPlayType == null) {return null;} - if (window.AudioContext) { - s.context = new AudioContext(); - } else if (window.webkitAudioContext) { + if (t.canPlayType == null) { + return null; + } + + // This check is first because it's what is currently used, but the spec calls for it to be AudioContext so this + // will probably change in time + if (window.webkitAudioContext) { s.context = new webkitAudioContext(); + } else if (window.AudioContext) { + s.context = new AudioContext(); } else { return null; } + // this handles if only deprecated Web Audio API calls are supported s._compatibilitySetUp(); // playing this inside of a touch event will enable audio on iOS, which starts muted @@ -2687,6 +2814,12 @@ this.createjs = this.createjs || {}; if (s.context.destination.numberOfChannels < 2) { s._capabilities.panning = false; } + + // set up AudioNodes that all of our source audio will connect to + s.dynamicsCompressorNode = s.context.createDynamicsCompressor(); + s.dynamicsCompressorNode.connect(s.context.destination); + s.gainNode = s.context.createGain(); + s.gainNode.connect(s.dynamicsCompressorNode); }; /** @@ -2696,12 +2829,10 @@ this.createjs = this.createjs || {}; * don't support new calls. * * @method _compatibilitySetUp - * @static * @protected * @since 0.4.2 */ s._compatibilitySetUp = function() { - s._panningModel = "equalpower"; //assume that if one new call is supported, they all are if (s.context.createGain) { return; } @@ -2714,7 +2845,7 @@ this.createjs = this.createjs || {}; audioNode.__proto__.stop = audioNode.__proto__.noteOff; // panningModel - s._panningModel = 0; + this._panningModel = 0; }; /** @@ -2724,18 +2855,24 @@ this.createjs = this.createjs || {}; * for example). * *

    Example

    + * * function handleTouch(event) { * createjs.WebAudioPlugin.playEmptySound(); * } * * @method playEmptySound - * @static * @since 0.4.1 */ s.playEmptySound = function() { - var source = s.context.createBufferSource(); - source.buffer = s.context.createBuffer(1, 1, 22050); - source.connect(s.context.destination); + // create empty buffer + var buffer = this.context.createBuffer(1, 1, 22050); + var source = this.context.createBufferSource(); + source.buffer = buffer; + + // connect to output (your speakers) + source.connect(this.context.destination); + + // play the file source.start(0, 0, 0); }; @@ -2751,6 +2888,7 @@ this.createjs = this.createjs || {}; * @default 1 * @protected */ + // TODO refactor Sound.js so we can use getter setter for volume p._volume = 1; /** @@ -2772,24 +2910,20 @@ this.createjs = this.createjs || {}; /** * A DynamicsCompressorNode, which is used to improve sound quality and prevent audio distortion. * It is connected to context.destination. - * - * Can be accessed by advanced users through createjs.Sound.activePlugin.dynamicsCompressorNode. * @property dynamicsCompressorNode * @type {AudioNode} */ p.dynamicsCompressorNode = null; /** - * A GainNode for controlling master volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}. - * - * Can be accessed by advanced users through createjs.Sound.activePlugin.gainNode. + * A GainNode for controlling master _volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}. * @property gainNode * @type {AudioGainNode} */ p.gainNode = null; /** - * An object hash used internally to store ArrayBuffers, indexed by the source URI used to load it. This + * An object hash used internally to store ArrayBuffers, indexed by the source URI used to load it. This * prevents having to load and decode audio files more than once. If a load has been started on a file, * arrayBuffers[src] will be set to true. Once load is complete, it is set the the loaded * ArrayBuffer instance. @@ -2809,13 +2943,8 @@ this.createjs = this.createjs || {}; this._arrayBuffers = {}; this.context = s.context; - this._panningModel = s._panningModel; - - // set up AudioNodes that all of our source audio will connect to - this.dynamicsCompressorNode = this.context.createDynamicsCompressor(); - this.dynamicsCompressorNode.connect(this.context.destination); - this.gainNode = this.context.createGain(); - this.gainNode.connect(this.dynamicsCompressorNode); + this.gainNode = s.gainNode; + this.dynamicsCompressorNode = s.dynamicsCompressorNode; }; /** @@ -2829,9 +2958,11 @@ this.createjs = this.createjs || {}; * @return {Object} A result object, containing a "tag" for preloading purposes. */ p.register = function (src, instances) { - this._arrayBuffers[src] = true; - var loader = {tag: new createjs.WebAudioPlugin.Loader(src, this)}; - return loader; + this._arrayBuffers[src] = true; // This is needed for PreloadJS + var tag = new createjs.WebAudioPlugin.Loader(src, this); + return { + tag:tag + }; }; /** @@ -2890,18 +3021,19 @@ this.createjs = this.createjs || {}; * @method _handlePreloadComplete * @protected */ - p._handlePreloadComplete = function (loader) { - createjs.Sound._sendFileLoadEvent(loader.src); - loader.cleanUp(); + p._handlePreloadComplete = function () { + //LM: I would recommend having the Loader include an "event" in the onload, and properly binding this callback. + createjs.Sound._sendFileLoadEvent(this.src); // fire event or callback on Sound + // note "this" will reference Loader object }; /** * Internally preload a sound. Loading uses XHR2 to load an array buffer for use with WebAudio. * @method preload * @param {String} src The sound URI to load. - * @param {Object} tag Not used in this plugin. + * @param {Object} instance Not used in this plugin. */ - p.preload = function (src, tag) { + p.preload = function (src, instance) { this._arrayBuffers[src] = true; var loader = new createjs.WebAudioPlugin.Loader(src, this); loader.onload = this._handlePreloadComplete; @@ -2915,7 +3047,9 @@ this.createjs = this.createjs || {}; * @return {SoundInstance} A sound instance for playback and control. */ p.create = function (src) { - if (!this.isPreloadStarted(src)) {this.preload(src);} + if (!this.isPreloadStarted(src)) { + this.preload(src); + } return new createjs.WebAudioPlugin.SoundInstance(src, this); }; @@ -2982,6 +3116,7 @@ this.createjs = this.createjs || {}; * for control by the user. * *

    Example

    + * * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3"); * * A number of additional parameters provide a quick way to determine how a sound is played. Please see the Sound @@ -3063,6 +3198,16 @@ this.createjs = this.createjs || {}; */ p._offset = 0; + /** + * The time in milliseconds before the sound starts. + * Note this is handled by {{#crossLink "Sound"}}{{/crossLink}}. + * @property _delay + * @type {Number} + * @default 0 + * @protected + */ + p._delay = 0; // OJR remove this property from SoundInstance as it is not used here? + /** * The volume of the sound, between 0 and 1. *
    Note this uses a getter setter, which is not supported by Firefox versions 3.6 or lower and Opera versions 11.50 or lower, @@ -3076,7 +3221,8 @@ this.createjs = this.createjs || {}; * @default 1 */ p._volume = 1; - if (createjs.definePropertySupported) { + // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors + try { Object.defineProperty(p, "volume", { get: function() { return this._volume; @@ -3088,7 +3234,9 @@ this.createjs = this.createjs || {}; this._updateVolume(); } }); - } + } catch (e) { + // dispatch message or error? + }; /** * The pan of the sound, between -1 (left) and 1 (right). Note that pan is not supported by HTML Audio. @@ -3102,7 +3250,8 @@ this.createjs = this.createjs || {}; * @default 0 */ p._pan = 0; - if (createjs.definePropertySupported) { + // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors + try { Object.defineProperty(p, "pan", { get: function() { return this._pan; @@ -3116,7 +3265,10 @@ this.createjs = this.createjs || {}; this.panNode.setPosition(value, 0, -0.5); // z need to be -0.5 otherwise the sound only plays in left, right, or center } }); - } + } catch (e) { + // dispatch message or error? + }; + /** * The length of the audio clip, in milliseconds. @@ -3139,7 +3291,7 @@ this.createjs = this.createjs || {}; /** * A Timeout created by {{#crossLink "Sound"}}{{/crossLink}} when this SoundInstance is played with a delay. - * This allows SoundInstance to remove the delay if stop, pause, or cleanup are called before playback begins. + * This allows SoundInstance to remove the delay if stop or pause or cleanup are called before playback begins. * @property _delayTimeoutId * @type {timeoutVariable} * @default null @@ -3280,6 +3432,43 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ + //TODO: Deprecated + /** + * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/succeeded:event"}}{{/crossLink}} + * event. + * @property onPlaySucceeded + * @type {Function} + * @deprecated Use addEventListener and the "succeeded" event. + */ + /** + * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/interrupted:event"}}{{/crossLink}} + * event. + * @property onPlayInterrupted + * @type {Function} + * @deprecated Use addEventListener and the "interrupted" event. + */ + /** + * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/failed:event"}}{{/crossLink}} + * event. + * @property onPlayFailed + * @type {Function} + * @deprecated Use addEventListener and the "failed" event. + */ + /** + * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/complete:event"}}{{/crossLink}} + * event. + * @property onComplete + * @type {Function} + * @deprecated Use addEventListener and the "complete" event. + */ + /** + * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "SoundInstance/loop:event"}}{{/crossLink}} + * event. + * @property onLoop + * @type {Function} + * @deprecated Use addEventListener and the "loop" event. + */ + /** * A helper method that dispatches all events for SoundInstance. * @method _sendEvent @@ -3300,16 +3489,18 @@ this.createjs = this.createjs || {}; * @protected */ p._init = function (src, owner) { - this.src = src; this._owner = owner; + this.src = src; this.gainNode = this._owner.context.createGain(); - this.panNode = this._owner.context.createPanner(); + this.panNode = this._owner.context.createPanner(); //TODO test how this affects when we have mono audio this.panNode.panningModel = this._owner._panningModel; this.panNode.connect(this.gainNode); - if (this._owner.isPreloadComplete(this.src)) {this._duration = this._owner._arrayBuffers[this.src].duration * 1000;} + if (this._owner.isPreloadComplete(this.src)) { + this._duration = this._owner._arrayBuffers[this.src].duration * 1000; + } this._endedHandler = createjs.proxy(this._handleSoundComplete, this); }; @@ -3325,7 +3516,9 @@ this.createjs = this.createjs || {}; this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); } - if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);} + if (this.gainNode.numberOfOutputs != 0) { + this.gainNode.disconnect(0); + } // this works because we only have one connection, and it returns 0 if we've already disconnected it. // OJR there appears to be a bug that this doesn't always work in webkit (Chrome and Safari). According to the documentation, this should work. clearTimeout(this._delayTimeoutId); // clear timeout that plays delayed sound @@ -3333,6 +3526,9 @@ this.createjs = this.createjs || {}; this._startTime = 0; // This is used by getPosition + if (window.createjs == null) { + return; + } createjs.Sound._playFinished(this); }; @@ -3348,7 +3544,7 @@ this.createjs = this.createjs || {}; if(audioNode) { audioNode.stop(0); audioNode.disconnect(this.panNode); - audioNode = null; + audioNode = null; // release reference so Web Audio can handle removing references and garbage collection } return audioNode; }; @@ -3371,7 +3567,11 @@ this.createjs = this.createjs || {}; * @protected */ p._handleSoundReady = function (event) { - if ((this._offset*1000) > this.getDuration()) { + if (window.createjs == null) { + return; + } + + if ((this._offset*1000) > this.getDuration()) { // converting offset to ms this.playFailed(); return; } else if (this._offset < 0) { // may not need this check if play ignores negative values, this is not specified in the API http://www.w3.org/TR/webaudio/#AudioBufferSourceNode @@ -3409,7 +3609,7 @@ this.createjs = this.createjs || {}; audioNode.buffer = this._owner._arrayBuffers[this.src]; audioNode.connect(this.panNode); var currentTime = this._owner.context.currentTime; - audioNode.startTime = startTime + audioNode.buffer.duration; + audioNode.startTime = startTime + audioNode.buffer.duration; //currentTime + audioNode.buffer.duration - (currentTime - startTime); audioNode.start(audioNode.startTime, offset, audioNode.buffer.duration - offset); return audioNode; }; @@ -3454,6 +3654,14 @@ this.createjs = this.createjs || {}; * @protected */ p._beginPlaying = function (offset, loop, volume, pan) { + if (window.createjs == null) { + return; + } + + if (!this.src) { + return; + } + this._offset = offset / 1000; //convert ms to sec this._remainingLoops = loop; this.volume = volume; @@ -3481,19 +3689,22 @@ this.createjs = this.createjs || {}; * @return {Boolean} If the pause call succeeds. This will return false if the sound isn't currently playing. */ p.pause = function () { - if (this._paused || this.playState != createjs.Sound.PLAY_SUCCEEDED) {return false;} + if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) { + this.paused = this._paused = true; - this.paused = this._paused = true; + this._offset = this._owner.context.currentTime - this._startTime; // this allows us to restart the sound at the same point in playback + this.sourceNode = this._cleanUpAudioNode(this.sourceNode); + this.sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); - this._offset = this._owner.context.currentTime - this._startTime; // this allows us to restart the sound at the same point in playback - this.sourceNode = this._cleanUpAudioNode(this.sourceNode); - this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); + if (this.gainNode.numberOfOutputs != 0) { + this.gainNode.disconnect(); + } // this works because we only have one connection, and it returns 0 if we've already disconnected it. - if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect();} - - clearTimeout(this._delayTimeoutId); - clearTimeout(this._soundCompleteTimeout); - return true; + clearTimeout(this._delayTimeoutId); // clear timeout that plays delayed sound + clearTimeout(this._soundCompleteTimeout); // clear timeout that triggers sound complete + return true; + } + return false; }; /** @@ -3510,8 +3721,10 @@ this.createjs = this.createjs || {}; * @return {Boolean} If the resume call succeeds. This will return false if called on a sound that is not paused. */ p.resume = function () { - if (!this._paused) {return false;} - this._handleSoundReady(); + if (!this._paused) { + return false; + } + this._handleSoundReady(null); return true; }; @@ -3551,20 +3764,23 @@ this.createjs = this.createjs || {}; */ p.setVolume = function (value) { this.volume = value; - return true; + return true; // This is always true because even if the volume is not updated, the value is set }; /** * Internal function used to update the volume based on the instance volume, master volume, instance mute value, * and master mute value. * @method _updateVolume + * @return {Boolean} if the volume was updated. * @protected */ p._updateVolume = function () { var newVolume = this._muted ? 0 : this._volume; if (newVolume != this.gainNode.gain.value) { this.gainNode.gain.value = newVolume; + return true; } + return false; }; /** @@ -3594,7 +3810,9 @@ this.createjs = this.createjs || {}; * @since 0.4.0 */ p.setMute = function (value) { - if (value == null) {return false;} + if (value == null || value == undefined) { + return false; + } this._muted = value; this._updateVolume(); @@ -3634,7 +3852,6 @@ this.createjs = this.createjs || {}; p.setPan = function (value) { this.pan = value; // Unfortunately panner does not give us a way to access this after it is set http://www.w3.org/TR/webaudio/#AudioPannerNode if(this.pan != value) {return false;} - return true; }; /** @@ -3695,7 +3912,9 @@ this.createjs = this.createjs || {}; clearTimeout(this._soundCompleteTimeout); // clear timeout that triggers sound complete } // NOTE we cannot just call cleanup because it also calls the Sound function _playFinished which releases this instance in SoundChannel - if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) {this._handleSoundReady();} + if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) { + this._handleSoundReady(null); + } return true; }; @@ -3741,13 +3960,16 @@ this.createjs = this.createjs || {}; this._soundCompleteTimeout = setTimeout(this._endedHandler, this._duration); } else { - this._handleSoundReady(); + this._handleSoundReady(null); } this._sendEvent("loop"); return; } + if (window.createjs == null) { + return; + } this._cleanUp(); this.playState = createjs.Sound.PLAY_FINISHED; this._sendEvent("complete"); @@ -3755,6 +3977,9 @@ this.createjs = this.createjs || {}; // Play has failed, which can happen for a variety of reasons. p.playFailed = function () { + if (window.createjs == null) { + return; + } this._cleanUp(); this.playState = createjs.Sound.PLAY_FAILED; this._sendEvent("failed"); @@ -3798,6 +4023,13 @@ this.createjs = this.createjs || {}; */ p.src = null; + /** + * The original source of the sound, before it is altered with a basePath. + * #property src + * @type {String} + */ + p.originalSrc = null; + /** * The decoded AudioBuffer array that is returned when loading is complete. * #property result @@ -3822,16 +4054,17 @@ this.createjs = this.createjs || {}; p.onprogress = null; /** - * The callback that fires if the load hits an error. This follows HTML tag naming. - * #property onerror + * The callback that fires if the load hits an error. + * #property onError * @type {Method} * @protected */ - p.onerror = null; + p.onError = null; // constructor p._init = function (src, owner) { this.src = src; + this.originalSrc = src; this.owner = owner; }; @@ -3841,13 +4074,16 @@ this.createjs = this.createjs || {}; * @param {String} src The path to the sound. */ p.load = function (src) { - if (src != null) {this.src = src;} + if (src != null) { + // TODO does this need to set this.originalSrc + this.src = src; + } this.request = new XMLHttpRequest(); this.request.open("GET", this.src, true); this.request.responseType = "arraybuffer"; this.request.onload = createjs.proxy(this.handleLoad, this); - this.request.onerror = createjs.proxy(this.handleError, this); + this.request.onError = createjs.proxy(this.handleError, this); this.request.onprogress = createjs.proxy(this.handleProgress, this); this.request.send(); @@ -3865,7 +4101,7 @@ this.createjs = this.createjs || {}; */ p.handleProgress = function (loaded, total) { this.progress = loaded / total; - this.onprogress && this.onprogress({loaded:loaded, total:total, progress:this.progress}); + this.onprogress != null && this.onprogress({loaded:loaded, total:total, progress:this.progress}); }; /** @@ -3887,8 +4123,9 @@ this.createjs = this.createjs || {}; p.handleAudioDecoded = function (decodedAudio) { this.progress = 1; this.result = decodedAudio; + this.src = this.originalSrc; this.owner.addPreloadResults(this.src, this.result); - this.onload && this.onload(this); + this.onload && this.onload(); }; /** @@ -3901,23 +4138,6 @@ this.createjs = this.createjs || {}; this.onerror && this.onerror(evt); }; - /** - * Remove all external references from loader - * #method cleanUp - */ - p.cleanUp = function () { - if(!this.request) {return;} - this.src = null; - this.owner = null; - this.request.onload = null; - this.request.onerror = null; - this.request.onprogress = null; - this.request = null; - this.onload = null; - this.onprogress = null; - this.onerror = null; - }; - p.toString = function () { return "[WebAudioPlugin Loader]"; }; @@ -3977,13 +4197,12 @@ this.createjs = this.createjs || {}; * tags are precreated to allow Chrome to load them. Please use {{#crossLink "Sound.MAX_INSTANCES"}}{{/crossLink}} as * a guide to how many total audio tags you can safely use in all browsers. * - * IE html limitations
    + * IE 9 html limitations
    *
    • There is a delay in applying volume changes to tags that occurs once playback is started. So if you have * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of * when or how you apply the volume change, as the tag seems to need to play to apply it.
    • *
    • MP3 encoding will not always work for audio tags if it's not default. We've found default encoding with * 64kbps works.
    • - *
    • Occasionally very short samples will get cut off.
    • *
    • There is a limit to how many audio tags you can load and play at once, which appears to be determined by * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate.
    * @@ -4106,9 +4325,14 @@ this.createjs = this.createjs || {}; * @static */ s.isSupported = function () { - if (createjs.Sound.BrowserDetect.isIOS && !s.enableIOS) {return false;} + if (createjs.Sound.BrowserDetect.isIOS && !s.enableIOS) { + return false; + } s._generateCapabilities(); - if (s._capabilities == null) {return false;} + var t = s.tag; // OJR do we still need this check, when cap will already be null if this is the case + if (t == null || s._capabilities == null) { + return false; + } return true; }; @@ -4120,9 +4344,13 @@ this.createjs = this.createjs || {}; * @protected */ s._generateCapabilities = function () { - if (s._capabilities != null) {return;} - var t = document.createElement("audio"); - if (t.canPlayType == null) {return null;} + if (s._capabilities != null) { + return; + } + var t = s.tag = document.createElement("audio"); + if (t.canPlayType == null) { + return null; + } s._capabilities = { panning:true, @@ -4155,7 +4383,7 @@ this.createjs = this.createjs || {}; p._audioSources = null; /** - * The default number of instances to allow. Used by {{#crossLink "Sound"}}{{/crossLink}} when a source + * The default number of instances to allow. Passed back to {{#crossLink "Sound"}}{{/crossLink}} when a source * is registered using the {{#crossLink "Sound/register"}}{{/crossLink}} method. This is only used if * a value is not provided. * @@ -4167,6 +4395,9 @@ this.createjs = this.createjs || {}; */ p.defaultNumChannels = 2; + // Proxies, make removing listeners easier. + p.loadedHandler = null; + /** * An initialization function run by the constructor * @method _init @@ -4191,17 +4422,52 @@ this.createjs = this.createjs || {}; this._audioSources[src] = true; // Note this does not mean preloading has started var channel = createjs.HTMLAudioPlugin.TagPool.get(src); var tag = null; - var l = instances; - for (var i = 0; i < l; i++) { + var l = instances || this.defaultNumChannels; + for (var i = 0; i < l; i++) { // OJR should we be enforcing s.MAX_INSTANCES here? Does the chrome bug still exist, or can we change this code? tag = this._createTag(src); channel.add(tag); } + tag.id = src; // co-opting id as we need a way to store original src in case it is changed before loading + this.loadedHandler = createjs.proxy(this._handleTagLoad, this); // we need this bind to be able to remove event listeners + tag.addEventListener && tag.addEventListener("canplaythrough", this.loadedHandler); + if(tag.onreadystatechange == null) { + tag.onreadystatechange = this.loadedHandler; + } else { + var f = tag.onreadystatechange; + // OJR will this lose scope? + tag.onreadystatechange = function() { + f(); + this.loadedHandler(); + } + } + return { - tag:tag // Return one instance for preloading purposes + tag:tag, // Return one instance for preloading purposes + numChannels:l // The default number of channels to make for this Sound or the passed in value }; }; + // TODO remove this when | approach is removed + /** + * Deprecated as this will not be required with new approach to basePath. + * Checks if src was changed on tag used to create instances in TagPool before loading + * Currently PreloadJS does this when a basePath is set, so we are replicating that behavior for internal preloading. + * @method _handleTagLoad + * @param event + * @protected + * @deprecated + */ + p._handleTagLoad = function(event) { + // cleanup and so we don't send the event more than once + event.target.removeEventListener && event.target.removeEventListener("canplaythrough", this.loadedHandler); + event.target.onreadystatechange = null; + + if (event.target.src == event.target.id) { return; } + // else src has changed before loading, and we need to make the change to TagPool because we pre create tags + createjs.HTMLAudioPlugin.TagPool.checkSrc(event.target.id); + }; + /** * Create an HTML audio tag. * @method _createTag @@ -4237,7 +4503,7 @@ this.createjs = this.createjs || {}; * @since 0.4.1 */ p.removeAllSounds = function () { - this._audioSources = {}; + this._audioSources = {}; // this drops all references, in theory freeing them for garbage collection createjs.HTMLAudioPlugin.TagPool.removeAll(); }; @@ -4275,12 +4541,12 @@ this.createjs = this.createjs || {}; * Internally preload a sound. * @method preload * @param {String} src The sound URI to load. - * @param {Object} tag An HTML audio tag used to load src. + * @param {Object} instance An object containing a tag property that is an HTML audio tag used to load src. * @since 0.4.0 */ - p.preload = function (src, tag) { + p.preload = function (src, instance) { this._audioSources[src] = true; - new createjs.HTMLAudioPlugin.Loader(src, tag); + new createjs.HTMLAudioPlugin.Loader(src, instance.tag); }; p.toString = function () { @@ -4309,8 +4575,10 @@ this.createjs = this.createjs || {}; p._owner = null; p.loaded = false; p._offset = 0; + p._delay = 0; p._volume = 1; - if (createjs.definePropertySupported) { + // IE8 has Object.defineProperty, but only for DOM objects, so check if fails to suppress errors + try { Object.defineProperty(p, "volume", { get: function() { return this._volume; @@ -4322,7 +4590,9 @@ this.createjs = this.createjs || {}; this._updateVolume(); } }); - } + } catch (e) { + // dispatch message or error? + }; p.pan = 0; p._duration = 0; p._remainingLoops = 0; @@ -4343,8 +4613,6 @@ this.createjs = this.createjs || {}; this.src = src; this._owner = owner; - this._duration = createjs.HTMLAudioPlugin.TagPool.getDuration(this.src); - this._endedHandler = createjs.proxy(this._handleSoundComplete, this); this._readyHandler = createjs.proxy(this._handleSoundReady, this); this._stalledHandler = createjs.proxy(this._handleSoundStalled, this); @@ -4372,11 +4640,16 @@ this.createjs = this.createjs || {}; } clearTimeout(this._delayTimeoutId); + if (window.createjs == null) { + return; + } createjs.Sound._playFinished(this); }; p._interrupt = function () { - if (this.tag == null) {return;} + if (this.tag == null) { + return; + } this.playState = createjs.Sound.PLAY_INTERRUPTED; this._cleanUp(); this.paused = this._paused = false; @@ -4385,11 +4658,14 @@ this.createjs = this.createjs || {}; // Public API p.play = function (interrupt, delay, offset, loop, volume, pan) { - this._cleanUp(); + this._cleanUp(); //LM: Is this redundant? createjs.Sound._playInstance(this, interrupt, delay, offset, loop, volume, pan); }; p._beginPlaying = function (offset, loop, volume, pan) { + if (window.createjs == null) { + return -1; + } var tag = this.tag = createjs.HTMLAudioPlugin.TagPool.getInstance(this.src); if (tag == null) { this.playFailed(); @@ -4401,7 +4677,8 @@ this.createjs = this.createjs || {}; // Reset this instance. this._offset = offset; this.volume = volume; - this._updateVolume(); + this.pan = pan; // not pan has no effect + this._updateVolume(); // note this will set for mute and _masterMute this._remainingLoops = loop; if (tag.readyState !== 4) { @@ -4420,17 +4697,24 @@ this.createjs = this.createjs || {}; // Note: Sounds stall when trying to begin playback of a new audio instance when the existing instances // has not loaded yet. This doesn't mean the sound will not play. p._handleSoundStalled = function (event) { - this._cleanUp(); // OJR this will stop playback, we could remove this and let the developer decide how to handle stalled instances + this._cleanUp(); // OJR NOTE this will stop playback, and I think we should remove this and let the developer decide how to handle stalled instances this._sendEvent("failed"); }; p._handleSoundReady = function (event) { + if (window.createjs == null) { + return; + } + + // OJR would like a cleaner way to do this in _init, discuss with LM + this._duration = this.tag.duration * 1000; // need this for setPosition on stopped sounds + this.playState = createjs.Sound.PLAY_SUCCEEDED; this.paused = this._paused = false; this.tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false); if (this._offset >= this.getDuration()) { - this.playFailed(); + this.playFailed(); // OJR: throw error? return; } else if (this._offset > 0) { this.tag.currentTime = this._offset * 0.001; @@ -4448,15 +4732,20 @@ this.createjs = this.createjs || {}; p.pause = function () { if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED && this.tag != null) { this.paused = this._paused = true; + // Note: when paused by user, we hold a reference to our tag. We do not release it until stopped. this.tag.pause(); + clearTimeout(this._delayTimeoutId); + return true; } return false; }; p.resume = function () { - if (!this._paused || this.tag == null) {return false;} + if (!this._paused || this.tag == null) { + return false; + } this.paused = this._paused = false; this.tag.play(); return true; @@ -4472,6 +4761,7 @@ this.createjs = this.createjs || {}; p.setMasterVolume = function (value) { this._updateVolume(); + return true; }; p.setVolume = function (value) { @@ -4482,7 +4772,12 @@ this.createjs = this.createjs || {}; p._updateVolume = function () { if (this.tag != null) { var newVolume = (this._muted || createjs.Sound._masterMute) ? 0 : this._volume * createjs.Sound._masterVolume; - if (newVolume != this.tag.volume) {this.tag.volume = newVolume;} + if (newVolume != this.tag.volume) { + this.tag.volume = newVolume; + } + return true; + } else { + return false; } }; @@ -4492,10 +4787,14 @@ this.createjs = this.createjs || {}; p.setMasterMute = function (isMuted) { this._updateVolume(); + return true; }; p.setMute = function (isMuted) { - if (isMuted == null) {return false;} + if (isMuted == null || isMuted == undefined) { + return false; + } + this._muted = isMuted; this._updateVolume(); return true; @@ -4505,7 +4804,7 @@ this.createjs = this.createjs || {}; return this._muted; }; - // Can not set pan in HTML audio + // Can not set pan in HTML p.setPan = function (value) { return false; }; @@ -4515,7 +4814,9 @@ this.createjs = this.createjs || {}; }; p.getPosition = function () { - if (this.tag == null) {return this._offset;} + if (this.tag == null) { + return this._offset; + } return this.tag.currentTime * 1000; }; @@ -4540,15 +4841,21 @@ this.createjs = this.createjs || {}; p._handleSoundComplete = function (event) { this._offset = 0; + + if (window.createjs == null) { + return; + } this.playState = createjs.Sound.PLAY_FINISHED; this._cleanUp(); this._sendEvent("complete"); }; + // handles looping functionality // NOTE with this approach audio will loop as reliably as the browser allows // but we could end up sending the loop event after next loop playback begins p.handleSoundLoop = function (event) { this._offset = 0; + this._remainingLoops--; if(this._remainingLoops == 0) { this.tag.loop = false; @@ -4558,6 +4865,9 @@ this.createjs = this.createjs || {}; }; p.playFailed = function () { + if (window.createjs == null) { + return; + } this.playState = createjs.Sound.PLAY_FAILED; this._cleanUp(); this._sendEvent("failed"); @@ -4636,12 +4946,12 @@ this.createjs = this.createjs || {}; this.loadedHandler = createjs.proxy(this.sendLoadedEvent, this); // we need this bind to be able to remove event listeners this.tag.addEventListener && this.tag.addEventListener("canplaythrough", this.loadedHandler); if(this.tag.onreadystatechange == null) { - this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); + this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); // OJR not 100% sure we need this, just copied from PreloadJS } else { var f = this.tag.onreadystatechange; this.tag.onreadystatechange = function() { f(); - this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); + this.tag.onreadystatechange = createjs.proxy(this.sendLoadedEvent, this); // OJR not 100% sure we need this, just copied from PreloadJS } } @@ -4684,7 +4994,6 @@ this.createjs = this.createjs || {}; this.tag.removeEventListener && this.tag.removeEventListener("canplaythrough", this.loadedHandler); // cleanup and so we don't send the event more than once this.tag.onreadystatechange = null; // cleanup and so we don't send the event more than once createjs.Sound._sendFileLoadEvent(this.src); // fire event or callback on Sound - }; // used for debugging @@ -4747,7 +5056,9 @@ this.createjs = this.createjs || {}; */ s.remove = function (src) { var channel = s.tags[src]; - if (channel == null) {return false;} + if (channel == null) { + return false; + } channel.removeAll(); delete(s.tags[src]); return true; @@ -4774,7 +5085,9 @@ this.createjs = this.createjs || {}; */ s.getInstance = function (src) { var channel = s.tags[src]; - if (channel == null) {return null;} + if (channel == null) { + return null; + } return channel.get(); }; @@ -4788,20 +5101,27 @@ this.createjs = this.createjs || {}; */ s.setInstance = function (src, tag) { var channel = s.tags[src]; - if (channel == null) {return null;} + if (channel == null) { + return null; + } return channel.set(tag); }; /** - * Gets the duration of the src audio in milliseconds - * #method getDuration - * @param {String} src The source file used by the audio tag. - * @return {Number} Duration of src in milliseconds + * A function to check if src has changed in the loaded audio tag. + * This is required because PreloadJS appends a basePath to the src before loading. + * Note this is currently only called when a change is detected + * #method checkSrc + * @param src the unaltered src that is used to store the channel. + * @static + * @protected */ - s.getDuration= function (src) { + s.checkSrc = function (src) { var channel = s.tags[src]; - if (channel == null) {return 0;} - return channel.getDuration(); + if (channel == null) { + return null; + } + channel.checkSrcChange(); }; var p = TagPool.prototype; @@ -4841,15 +5161,6 @@ this.createjs = this.createjs || {}; */ p.tags = null; - /** - * The duration property of all audio tags, converted to milliseconds, which originally is only available on the - * last tag in the tags array because that is the one that is loaded. - * #property - * @type {Number} - * @protected - */ - p.duration = 0; - // constructor p._init = function (src) { this.src = src; @@ -4886,10 +5197,14 @@ this.createjs = this.createjs || {}; * @return {HTMLAudioElement} An HTML audio tag. */ p.get = function () { - if (this.tags.length == 0) {return null;} + if (this.tags.length == 0) { + return null; + } this.available = this.tags.length; var tag = this.tags.pop(); - if (tag.parentNode == null) {document.body.appendChild(tag);} + if (tag.parentNode == null) { + document.body.appendChild(tag); + } return tag; }; @@ -4900,19 +5215,26 @@ this.createjs = this.createjs || {}; */ p.set = function (tag) { var index = createjs.indexOf(this.tags, tag); - if (index == -1) {this.tags.push(tag);} + if (index == -1) { + this.tags.push(tag); + } this.available = this.tags.length; }; /** - * Gets the duration for the src audio and on first call stores it to this.duration - * #method getDuration - * @return {Number} Duration of the src in milliseconds + * Make sure the src of all other tags is correct after load. + * This is needed because PreloadJS appends a basePath to src before loading. + * #method checkSrcChange */ - p.getDuration = function () { - // this will work because this will be only be run the first time a sound instance is created and before any tags are taken from the pool - if (!this.duration) {this.duration = this.tags[this.tags.length - 1].duration * 1000;} - return this.duration; + p.checkSrcChange = function () { + // the last tag always has the latest src after loading + //var i = this.length-1; // this breaks in Firefox because it is not correctly removing an event listener + var i = this.tags.length - 1; + if(i == -1) return; // CodeCombat addition; sometimes errors in IE without this... + var newSrc = this.tags[i].src; + while(i--) { + this.tags[i].src = newSrc; + } }; p.toString = function () { From 004bcb8b97b4af50fcae54c75ad97fa9834a88b7 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 22 Mar 2014 10:12:47 -0700 Subject: [PATCH 12/30] Added the new WebGL enhanced classes for EaselJS. --- bin/coco-update-createjs | 2 + vendor/scripts/SpriteContainer.js | 188 ++++++ vendor/scripts/SpriteStage.js | 1030 +++++++++++++++++++++++++++++ 3 files changed, 1220 insertions(+) create mode 100644 vendor/scripts/SpriteContainer.js create mode 100644 vendor/scripts/SpriteStage.js diff --git a/bin/coco-update-createjs b/bin/coco-update-createjs index 5cd3f9140..b4871f47d 100755 --- a/bin/coco-update-createjs +++ b/bin/coco-update-createjs @@ -56,6 +56,8 @@ grunt combine echo moving to CoCo cp ~/Desktop/CreateJS/EaselJS/build/output/easeljs-NEXT.combined.js ~/Desktop/coco/vendor/scripts cp ~/Desktop/CreateJS/EaselJS/build/output/movieclip-NEXT.min.js ~/Desktop/coco/vendor/scripts +cp ~/Desktop/CreateJS/EaselJS/src/easeljs/display/SpriteStage.js ~/Desktop/coco/vendor/scripts/ +cp ~/Desktop/CreateJS/EaselJS/src/easeljs/display/SpriteContainer.js ~/Desktop/coco/vendor/scripts/ cp ~/Desktop/CreateJS/SoundJS/build/output/soundjs-NEXT.combined.js ~/Desktop/coco/vendor/scripts cp ~/Desktop/CreateJS/PreloadJS/build/output/preloadjs-NEXT.combined.js ~/Desktop/coco/vendor/scripts cp ~/Desktop/CreateJS/TweenJS/build/output/tweenjs-NEXT.combined.js ~/Desktop/coco/vendor/scripts diff --git a/vendor/scripts/SpriteContainer.js b/vendor/scripts/SpriteContainer.js new file mode 100644 index 000000000..49f31a26f --- /dev/null +++ b/vendor/scripts/SpriteContainer.js @@ -0,0 +1,188 @@ +/* +* SpriteContainer +* Visit http://createjs.com/ for documentation, updates and examples. +* +* Copyright (c) 2010 gskinner.com, inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +// namespace: +this.createjs = this.createjs||{}; + +(function() { + +/** + * A SpriteContainer is a nestable display list that enables aggressively optimized rendering of bitmap content. + * In order to accomplish these optimizations, SpriteContainer enforces a few restrictions on its content. + * + * Restrictions: + * - only Sprite, SpriteContainer, BitmapText and DOMElement are allowed to be added as children. + * - a spriteSheet MUST be either be passed into the constructor or defined on the first child added. + * - all children (with the exception of DOMElement) MUST use the same spriteSheet. + * + *

    Example

    + * var data = { + * images: ["sprites.jpg"], + * frames: {width:50, height:50}, + * animations: {run:[0,4], jump:[5,8,"run"]} + * }; + * var spriteSheet = new createjs.SpriteSheet(data); + * var container = new createjs.SpriteContainer(spriteSheet); + * container.addChild(spriteInstance, spriteInstance2); + * container.x = 100; + * + * Note: SpriteContainer is not included in the minified version of EaselJS. + * + * @class SpriteContainer + * @extends Container + * @constructor + * @param {SpriteSheet} [spriteSheet] The spriteSheet to use for this SpriteContainer and its children. + **/ +var SpriteContainer = function(spriteSheet) { + this.initialize(spriteSheet); +}; +var p = SpriteContainer.prototype = new createjs.Container(); + +// public properties: + + /** + * The SpriteSheet that this container enforces use of. + * @property spriteSheet + * @type {SpriteSheet} + * @readonly + **/ + p.spriteSheet = null; + +// constructor: + + /** + * @property Container_initialize + * @type Function + * @private + **/ + p.Container_initialize = p.initialize; + + /** + * Initialization method. + * @method initialize + * @param {SpriteSheet} spriteSheet Optional. The spriteSheet to use for this SpriteContainer and its children. + * @protected + */ + p.initialize = function(spriteSheet) { + this.Container_initialize(); + this.spriteSheet = spriteSheet; + }; + +// public methods: + + /** + * Adds a child to the top of the display list. + * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed. + * The child must have the same spritesheet as this container (unless it's a DOMElement). + * If a spritesheet hasn't been defined, this container uses this child's spritesheet. + * + *

    Example

    + * container.addChild(bitmapInstance); + * + * You can also add multiple children at once: + * + * container.addChild(bitmapInstance, shapeInstance, textInstance); + * + * @method addChild + * @param {DisplayObject} child The display object to add. + * @return {DisplayObject} The child that was added, or the last child if multiple children were added. + **/ + p.addChild = function(child) { + if (child == null) { return child; } + if (arguments.length > 1) { + return this.addChildAt.apply(this, Array.prototype.slice.call(arguments).concat([this.children.length])); + } else { + return this.addChildAt(child, this.children.length); + } + }; + + /** + * Adds a child to the display list at the specified index, bumping children at equal or greater indexes up one, and + * setting its parent to this Container. + * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed. + * The child must have the same spritesheet as this container (unless it's a DOMElement). + * If a spritesheet hasn't been defined, this container uses this child's spritesheet. + * + *

    Example

    + * addChildAt(child1, index); + * + * You can also add multiple children, such as: + * + * addChildAt(child1, child2, ..., index); + * + * The index must be between 0 and numChildren. For example, to add myShape under otherShape in the display list, + * you could use: + * + * container.addChildAt(myShape, container.getChildIndex(otherShape)); + * + * This would also bump otherShape's index up by one. Fails silently if the index is out of range. + * + * @method addChildAt + * @param {DisplayObject} child The display object to add. + * @param {Number} index The index to add the child at. + * @return {DisplayObject} Returns the last child that was added, or the last child if multiple children were added. + **/ + p.addChildAt = function(child, index) { + var l = arguments.length; + var indx = arguments[l-1]; // can't use the same name as the index param or it replaces arguments[1] + if (indx < 0 || indx > this.children.length) { return arguments[l-2]; } + if (l > 2) { + for (var i=0; i= 1) { + // The child is compatible with SpriteStage/SpriteContainer. + } else { + console && console.log("Error: You can only add children of type SpriteContainer, Sprite, BitmapText, or DOMElement [" + child.toString() + "]"); + return child; + } + if (child._spritestage_compatibility <= 4) { + var spriteSheet = child.spriteSheet; + if ((!spriteSheet || !spriteSheet._images || spriteSheet._images.length > 1) || (this.spritesheet && spritesheet !== spritesheet)) { + console && console.log("Error: A child's spriteSheet must be equal to its parent spriteSheet and only use one image. [" + child.toString() + "]"); + return child; + } + this.spriteSheet = spriteSheet; + } + if (child.parent) { child.parent.removeChild(child); } + child.parent = this; + this.children.splice(index, 0, child); + return child; + }; + + /** + * Returns a string representation of this object. + * @method toString + * @return {String} a string representation of the instance. + **/ + p.toString = function() { + return "[SpriteContainer (name="+ this.name +")]"; + }; + +createjs.SpriteContainer = SpriteContainer; +}()); \ No newline at end of file diff --git a/vendor/scripts/SpriteStage.js b/vendor/scripts/SpriteStage.js new file mode 100644 index 000000000..926de4a71 --- /dev/null +++ b/vendor/scripts/SpriteStage.js @@ -0,0 +1,1030 @@ +/* +* SpriteStage +* Visit http://createjs.com/ for documentation, updates and examples. +* +* Copyright (c) 2010 gskinner.com, inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * @module EaselJS + */ + +// namespace: +this.createjs = this.createjs||{}; + +(function() { + "use strict"; + +// Set which classes are compatible with SpriteStage. +// The order is important!!! If it's changed/appended, make sure that any logic that +// checks _spritestage_compatibility accounts for it! +[createjs.SpriteContainer, createjs.Sprite, createjs.BitmapText, createjs.Bitmap, createjs.DOMElement].forEach(function(_class, index) { + _class.prototype._spritestage_compatibility = index + 1; +}); + +/** + * A sprite stage is the root level {{#crossLink "Container"}}{{/crossLink}} for an aggressively optimized display list. Each time its {{#crossLink "Stage/tick"}}{{/crossLink}} + * method is called, it will render its display list to its target canvas. WebGL content is fully compatible with the existing Context2D renderer. + * On devices or browsers that don't support WebGL, content will automatically be rendered via canvas 2D. + * + * Restrictions: + * - only Sprite, SpriteContainer, BitmapText, Bitmap and DOMElement are allowed to be added to the display list. + * - a child being added (with the exception of DOMElement) MUST have an image or spriteSheet defined on it. + * - a child's image/spriteSheet MUST never change while being on the display list. + * + *

    Example

    + * This example creates a sprite stage, adds a child to it, then uses {{#crossLink "Ticker"}}{{/crossLink}} to update the child + * and redraw the stage using {{#crossLink "SpriteStage/update"}}{{/crossLink}}. + * + * var stage = new createjs.SpriteStage("canvasElementId", false, false); + * stage.updateViewport(800, 600); + * var image = new createjs.Bitmap("imagePath.png"); + * stage.addChild(image); + * createjs.Ticker.addEventListener("tick", handleTick); + * function handleTick(event) { + * image.x += 10; + * stage.update(); + * } + * + * Note: SpriteStage is not included in the minified version of EaselJS. + * + * @class SpriteStage + * @extends Stage + * @constructor + * @param {HTMLCanvasElement | String | Object} canvas A canvas object that the SpriteStage will render to, or the string id + * of a canvas object in the current document. + * @param {Boolean} preserveDrawingBuffer If true, the canvas is NOT auto-cleared by WebGL (spec discourages true). Useful if you want to use p.autoClear = false. + * @param {Boolean} antialias Specifies whether or not the browser's WebGL implementation should try to perform antialiasing. + **/ +var SpriteStage = function(canvas, preserveDrawingBuffer, antialias) { + this.initialize(canvas, preserveDrawingBuffer, antialias); +}; +var p = SpriteStage.prototype = new createjs.Stage(); + +// static properties: + + /** + * The number of properties defined per vertex in p._verticesBuffer. + * x, y, textureU, textureV, alpha + * @property NUM_VERTEX_PROPERTIES + * @static + * @final + * @type {Number} + * @readonly + **/ + SpriteStage.NUM_VERTEX_PROPERTIES = 5; + + /** + * The number of points in a box...obviously :) + * @property POINTS_PER_BOX + * @static + * @final + * @type {Number} + * @readonly + **/ + SpriteStage.POINTS_PER_BOX = 4; + + /** + * The number of vertex properties per box. + * @property NUM_VERTEX_PROPERTIES_PER_BOX + * @static + * @final + * @type {Number} + * @readonly + **/ + SpriteStage.NUM_VERTEX_PROPERTIES_PER_BOX = SpriteStage.POINTS_PER_BOX * SpriteStage.NUM_VERTEX_PROPERTIES; + + /** + * The number of indices needed to define a box using triangles. + * 6 indices = 2 triangles = 1 box + * @property INDICES_PER_BOX + * @static + * @final + * @type {Number} + * @readonly + **/ + SpriteStage.INDICES_PER_BOX = 6; + + /** + * The maximum size WebGL allows for element index numbers: 16 bit unsigned integer + * @property MAX_INDEX_SIZE + * @static + * @final + * @type {Number} + * @readonly + **/ + SpriteStage.MAX_INDEX_SIZE = Math.pow(2, 16); + + /** + * The amount used to increment p._maxBoxesPointsPerDraw when the maximum has been reached. + * If the maximum size of element index WebGL allows for (SpriteStage.MAX_INDEX_SIZE) was used, + * the array size for p._vertices would equal 1280kb and p._indices 192kb. But since mobile phones + * with less memory need to be accounted for, the maximum size is somewhat arbitrarily divided by 4, + * reducing the array sizes to 320kb and 48kb respectively. + * @property MAX_BOXES_POINTS_INCREMENT + * @static + * @final + * @type {Number} + * @readonly + **/ + SpriteStage.MAX_BOXES_POINTS_INCREMENT = SpriteStage.MAX_INDEX_SIZE / 4; + +// getter / setters: + /** + * Indicates whether WebGL is being used for rendering. For example, this would be false if WebGL is not + * supported in the browser. + * @readonly + * @property isWebGL + * @type {Boolean} + **/ + p._get_isWebGL = function() { + return !!this._webGLContext; + }; + + try { + Object.defineProperties(p, { + isWebGL: { get: p._get_isWebGL } + }); + } catch (e) {} // TODO: use Log + +// private properties: + + /** + * Specifies whether or not the canvas is auto-cleared by WebGL. Spec discourages true. + * If true, the canvas is NOT auto-cleared by WebGL. Value is ignored if p._alphaEnabled is false. + * Useful if you want to use p.autoClear = false. + * @property _preserveDrawingBuffer + * @protected + * @type {Boolean} + * @default false + **/ + p._preserveDrawingBuffer = false; + + /** + * Specifies whether or not the browser's WebGL implementation should try to perform antialiasing. + * @property _antialias + * @protected + * @type {Boolean} + * @default false + **/ + p._antialias = false; + + /** + * The width of the canvas element. + * @property _viewportWidth + * @protected + * @type {Number} + * @default 0 + **/ + p._viewportWidth = 0; + + /** + * The height of the canvas element. + * @property _viewportHeight + * @protected + * @type {Number} + * @default 0 + **/ + p._viewportHeight = 0; + + /** + * A 2D projection matrix used to convert WebGL's clipspace into normal pixels. + * @property _projectionMatrix + * @protected + * @type {Float32Array} + * @default null + **/ + p._projectionMatrix = null; + + /** + * The current WebGL canvas context. + * @property _webGLContext + * @protected + * @type {WebGLRenderingContext} + * @default null + **/ + p._webGLContext = null; + + /** + * Indicates whether or not an error has been detected when dealing with WebGL. + * If the is true, the behavior should be to use Canvas 2D rendering instead. + * @property _webGLErrorDetected + * @protected + * @type {Boolean} + * @default false + **/ + p._webGLErrorDetected = false; + + /** + * The color to use when the WebGL canvas has been cleared. + * @property _clearColor + * @protected + * @type {Object} + * @default null + **/ + p._clearColor = null; + + /** + * The maximum number of textures WebGL can work with per draw call. + * @property _maxTexturesPerDraw + * @protected + * @type {Number} + * @default 1 + **/ + p._maxTexturesPerDraw = 1; + + /** + * The maximum total number of boxes points that can be defined per draw call. + * @property _maxBoxesPointsPerDraw + * @protected + * @type {Number} + * @default null + **/ + p._maxBoxesPointsPerDraw = null; + + /** + * The maximum number of boxes (sprites) that can be drawn in one draw call. + * @property _maxBoxesPerDraw + * @protected + * @type {Number} + * @default null + **/ + p._maxBoxesPerDraw = null; + + /** + * The maximum number of indices that can be drawn in one draw call. + * @property _maxIndicesPerDraw + * @protected + * @type {Number} + * @default null + **/ + p._maxIndicesPerDraw = null; + + /** + * The shader program used to draw everything. + * @property _shaderProgram + * @protected + * @type {WebGLProgram} + * @default null + **/ + p._shaderProgram = null; + + /** + * The vertices data for the current draw call. + * @property _vertices + * @protected + * @type {Float32Array} + * @default null + **/ + p._vertices = null; + + /** + * The buffer that contains all the vertices data. + * @property _verticesBuffer + * @protected + * @type {WebGLBuffer} + * @default null + **/ + p._verticesBuffer = null; + + /** + * The indices to the vertices defined in p._vertices. + * @property _indices + * @protected + * @type {Uint16Array} + * @default null + **/ + p._indices = null; + + /** + * The buffer that contains all the indices data. + * @property _indicesBuffer + * @protected + * @type {WebGLBuffer} + * @default null + **/ + p._indicesBuffer = null; + + /** + * The current box index being defined for drawing. + * @property _currentBoxIndex + * @protected + * @type {Number} + * @default -1 + **/ + p._currentBoxIndex = -1; + + /** + * The current texture that will be used to draw into the GPU. + * @property _drawTexture + * @protected + * @type {WebGLTexture} + * @default null + **/ + p._drawTexture = null; + +// constructor: + + /** + * @property Stage_initialize + * @type Function + * @private + **/ + p.Stage_initialize = p.initialize; + + /** + * Initialization method. + * @method initialize + * @param {HTMLCanvasElement | String | Object} canvas A canvas object, or the string id of a canvas object in the current document. + * @param {Boolean} preserveDrawingBuffer If true, the canvas is NOT auto-cleared by WebGL (spec discourages true). Useful if you want to use p.autoClear = false. + * @param {Boolean} antialias Specifies whether or not the browser's WebGL implementation should try to perform antialiasing. + * @protected + **/ + p.initialize = function(canvas, preserveDrawingBuffer, antialias) { + this._preserveDrawingBuffer = preserveDrawingBuffer !== undefined ? preserveDrawingBuffer : this._preserveDrawingBuffer; + this._antialias = antialias !== undefined ? antialias : this._antialias; + + this.Stage_initialize(canvas); + this._initializeWebGL(); + }; + +// public methods: + + /** + * Adds a child to the top of the display list. + * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed. + * Children also MUST have either an image or spriteSheet defined on them (unless it's a DOMElement). + * + *

    Example

    + * container.addChild(bitmapInstance); + * + * You can also add multiple children at once: + * + * container.addChild(bitmapInstance, shapeInstance, textInstance); + * + * @method addChild + * @param {DisplayObject} child The display object to add. + * @return {DisplayObject} The child that was added, or the last child if multiple children were added. + **/ + p.addChild = function(child) { + if (child == null) { return child; } + if (arguments.length > 1) { + return this.addChildAt.apply(this, Array.prototype.slice.call(arguments).concat([this.children.length])); + } else { + return this.addChildAt(child, this.children.length); + } + }; + + /** + * Adds a child to the display list at the specified index, bumping children at equal or greater indexes up one, and + * setting its parent to this Container. + * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed. + * Children also MUST have either an image or spriteSheet defined on them (unless it's a DOMElement). + * + *

    Example

    + * addChildAt(child1, index); + * + * You can also add multiple children, such as: + * + * addChildAt(child1, child2, ..., index); + * + * The index must be between 0 and numChildren. For example, to add myShape under otherShape in the display list, + * you could use: + * + * container.addChildAt(myShape, container.getChildIndex(otherShape)); + * + * This would also bump otherShape's index up by one. Fails silently if the index is out of range. + * + * @method addChildAt + * @param {DisplayObject} child The display object to add. + * @param {Number} index The index to add the child at. + * @return {DisplayObject} Returns the last child that was added, or the last child if multiple children were added. + **/ + p.addChildAt = function(child, index) { + var l = arguments.length; + var indx = arguments[l-1]; // can't use the same name as the index param or it replaces arguments[1] + if (indx < 0 || indx > this.children.length) { return arguments[l-2]; } + if (l > 2) { + for (var i=0; i= 1) { + // The child is compatible with SpriteStage. + } else { + console && console.log("Error: You can only add children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement. [" + child.toString() + "]"); + return child; + } + if (!child.image && !child.spriteSheet && child._spritestage_compatibility <= 4) { + console && console.log("Error: You can only add children that have an image or spriteSheet defined on them. [" + child.toString() + "]"); + return child; + } + if (child.parent) { child.parent.removeChild(child); } + child.parent = this; + this.children.splice(index, 0, child); + this._setUpKidTexture(this._webGLContext, child); + return child; + }; + + /** + * Each time the update method is called, the stage will tick all descendants (see: {{#crossLink "DisplayObject/tick"}}{{/crossLink}}) + * and then render the display list to the canvas using WebGL. If WebGL is not supported in the browser, it will default to a 2D context. + * + * Any parameters passed to `update()` will be passed on to any + * {{#crossLink "DisplayObject/tick:event"}}{{/crossLink}} event handlers. + * + * Some time-based features in EaselJS (for example {{#crossLink "Sprite/framerate"}}{{/crossLink}} require that + * a tick event object (or equivalent) be passed as the first parameter to update(). For example: + * + * Ticker.addEventListener("tick", handleTick); + * function handleTick(evtObj) { + * // do some work here, then update the stage, passing through the event object: + * myStage.update(evtObj); + * } + * + * @method update + * @param {*} [params]* Params to include when ticking descendants. The first param should usually be a tick event. + **/ + p.update = function(params) { + if (!this.canvas) { return; } + if (this.tickOnUpdate) { + this.dispatchEvent("tickstart"); // TODO: make cancellable? + this._tick((arguments.length ? arguments : null)); + this.dispatchEvent("tickend"); + } + this.dispatchEvent("drawstart"); // TODO: make cancellable? + if (this.autoClear) { this.clear(); } + var ctx = this._setWebGLContext(); + if (ctx) { + // Use WebGL. + this.draw(ctx, false); + } else { + // Use 2D. + ctx = this.canvas.getContext("2d"); + ctx.save(); + this.updateContext(ctx); + this.draw(ctx, false); + ctx.restore(); + } + this.dispatchEvent("drawend"); + }; + + /** + * Clears the target canvas. Useful if {{#crossLink "Stage/autoClear:property"}}{{/crossLink}} is set to `false`. + * @method clear + **/ + p.clear = function() { + if (!this.canvas) { return; } + var ctx = this._setWebGLContext(); + if (ctx) { + // Use WebGL. + ctx.clear(ctx.COLOR_BUFFER_BIT); + } else { + // Use 2D. + ctx = this.canvas.getContext("2d"); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1); + } + }; + + /** + * @property Stage_draw + * @type {Function} + * @private + **/ + p.Stage_draw = p.draw; + + /** + * Draws the stage into the specified context (using WebGL) ignoring its visible, alpha, shadow, and transform. + * If WebGL is not supported in the browser, it will default to a 2D context. + * Returns true if the draw was handled (useful for overriding functionality). + * + * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. + * @method draw + * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. + * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. + * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back + * into itself). + **/ + p.draw = function(ctx, ignoreCache) { + if (ctx === this._webGLContext || ctx instanceof WebGLRenderingContext) { + this._drawWebGLKids(this.children, ctx); + + // If there is a remaining texture, draw it: + if (this._drawTexture) { + this._drawToGPU(ctx); + } + + return true; + } else { + return this.Stage_draw(ctx, ignoreCache); + } + }; + + /** + * Update the WebGL viewport. Note that this does NOT update the canvas element's width/height. + * @method updateViewport + * @param {Number} width + * @param {Number} height + **/ + p.updateViewport = function (width, height) { + this._viewportWidth = width; + this._viewportHeight = height; + + if (this._webGLContext) { + this._webGLContext.viewport(0, 0, this._viewportWidth, this._viewportHeight); + + if (!this._projectionMatrix) { + this._projectionMatrix = new Float32Array([0, 0, 0, 0, 0, 1, -1, 1, 1]); + } + this._projectionMatrix[0] = 2 / width; + this._projectionMatrix[4] = -2 / height; + } + }; + + /** + * Clears an image's texture to free it up for garbage collection. + * @method clearImageTexture + * @param {Image} image + **/ + p.clearImageTexture = function(image) { + image.__easeljs_texture = null; + }; + + /** + * Returns a string representation of this object. + * @method toString + * @return {String} a string representation of the instance. + **/ + p.toString = function() { + return "[SpriteStage (name="+ this.name +")]"; + }; + + // private methods: + + /** + * Initializes rendering with WebGL using the current canvas element. + * @method _initializeWebGL + * @protected + **/ + p._initializeWebGL = function() { + this._clearColor = { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }; + + this._setWebGLContext(); + }; + + /** + * Sets the WebGL context to use for future draws. + * @method _setWebGLContext + * @return {WebGLRenderingContext} The newly created context. + * @protected + **/ + p._setWebGLContext = function() { + if (this.canvas) { + if (!this._webGLContext || this._webGLContext.canvas !== this.canvas) { + // A context hasn't been defined yet, + // OR the defined context belongs to a different canvas, so reinitialize. + this._initializeWebGLContext(); + } + } else { + this._webGLContext = null; + } + return this._webGLContext; + }; + + /** + * Sets up the WebGL context for rendering. + * @method _initializeWebGLContext + * @protected + **/ + p._initializeWebGLContext = function() { + var options = { + depth: false, // Disable the depth buffer as it isn't used. + alpha: true, // Make the canvas background transparent. + preserveDrawingBuffer: this._preserveDrawingBuffer, + antialias: this._antialias, + premultipliedAlpha: true // Assume the drawing buffer contains colors with premultiplied alpha. + }; + var ctx = this._webGLContext = this.canvas.getContext("webgl", options) || this.canvas.getContext("experimental-webgl", options); + + if (!ctx) { + // WebGL is not supported in this browser. + return; + } + + // Enforcing 1 texture per draw for now until an optimized implementation for multiple textures is made: + this._maxTexturesPerDraw = 1; // ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS); + + // Set the default color the canvas should render when clearing: + this._setClearColor(this._clearColor.r, this._clearColor.g, this._clearColor.b, this._clearColor.a); + + // Enable blending and set the blending functions that work with the premultiplied alpha settings: + ctx.enable(ctx.BLEND); + ctx.blendFuncSeparate(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA, ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); + + // Do not premultiply textures' alpha channels when loading them in: + ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); + + // Create the shader program that will be used for drawing: + this._createShaderProgram(ctx); + + if (this._webGLErrorDetected) { + // Error detected during this._createShaderProgram(). + this._webGLContext = null; + return; + } + + // Create the vertices and indices buffers. + this._createBuffers(ctx); + + // Update the viewport with the initial canvas dimensions: + this.updateViewport(this._viewportWidth || this.canvas.width || 0, this._viewportHeight || this.canvas.height || 0); + }; + + /** + * Sets the color to use when the WebGL canvas has been cleared. + * @method _setClearColor + * @param {Number} r A number between 0 and 1. + * @param {Number} g A number between 0 and 1. + * @param {Number} b A number between 0 and 1. + * @param {Number} a A number between 0 and 1. + * @protected + **/ + p._setClearColor = function (r, g, b, a) { + this._clearColor.r = r; + this._clearColor.g = g; + this._clearColor.b = b; + this._clearColor.a = a; + + if (this._webGLContext) { + this._webGLContext.clearColor(r, g, b, a); + } + }; + + /** + * Creates the shader program that's going to be used to draw everything. + * @method _createShaderProgram + * @param {WebGLRenderingContext} ctx + * @protected + **/ + p._createShaderProgram = function(ctx) { + + + var fragmentShader = this._createShader(ctx, ctx.FRAGMENT_SHADER, + "precision mediump float;" + + + "uniform sampler2D uSampler0;" + + + "varying vec3 vTextureCoord;" + + + "void main(void) {" + + "vec4 color = texture2D(uSampler0, vTextureCoord.st);" + + "gl_FragColor = vec4(color.rgb, color.a * vTextureCoord.z);" + + "}" + ); + + var vertexShader = this._createShader(ctx, ctx.VERTEX_SHADER, + "attribute vec2 aVertexPosition;" + + "attribute vec3 aTextureCoord;" + + + "uniform mat3 uPMatrix;" + + + "varying vec3 vTextureCoord;" + + + "void main(void) {" + + "vTextureCoord = aTextureCoord;" + + + "gl_Position = vec4((uPMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" + + "}" + ); + + if (this._webGLErrorDetected || !fragmentShader || !vertexShader) { return; } + + var program = ctx.createProgram(); + ctx.attachShader(program, fragmentShader); + ctx.attachShader(program, vertexShader); + ctx.linkProgram(program); + + if(!ctx.getProgramParameter(program, ctx.LINK_STATUS)) { + // alert("Could not link program. " + ctx.getProgramInfoLog(program)); + this._webGLErrorDetected = true; + return; + } + + program.vertexPositionAttribute = ctx.getAttribLocation(program, "aVertexPosition"); + program.textureCoordAttribute = ctx.getAttribLocation(program, "aTextureCoord"); + + program.sampler0uniform = ctx.getUniformLocation(program, "uSampler0"); + + ctx.enableVertexAttribArray(program.vertexPositionAttribute); + ctx.enableVertexAttribArray(program.textureCoordAttribute); + + program.pMatrixUniform = ctx.getUniformLocation(program, "uPMatrix"); + + ctx.useProgram(program); + + this._shaderProgram = program; + }; + + /** + * Creates a shader from the specified string. + * @method _createShader + * @param {WebGLRenderingContext} ctx + * @param {Number} type The type of shader to create. + * @param {String} str The definition for the shader. + * @return {WebGLShader} + * @protected + **/ + p._createShader = function(ctx, type, str) { + var shader = ctx.createShader(type); + ctx.shaderSource(shader, str); + ctx.compileShader(shader); + + if (!ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) { + // alert("Could not compile shader. " + ctx.getShaderInfoLog(shader)); + this._webGLErrorDetected = true; + return null; + } + + return shader; + }; + + /** + * Sets up the necessary vertices and indices buffers. + * @method _createBuffers + * @param {WebGLRenderingContext} ctx + * @protected + **/ + p._createBuffers = function(ctx) { + this._verticesBuffer = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer); + + var byteCount = SpriteStage.NUM_VERTEX_PROPERTIES * 4; // ctx.FLOAT = 4 bytes + ctx.vertexAttribPointer(this._shaderProgram.vertexPositionAttribute, 2, ctx.FLOAT, ctx.FALSE, byteCount, 0); + ctx.vertexAttribPointer(this._shaderProgram.textureCoordAttribute, 3, ctx.FLOAT, ctx.FALSE, byteCount, 2 * 4); + + this._indicesBuffer = ctx.createBuffer(); + + this._setMaxBoxesPoints(ctx, SpriteStage.MAX_BOXES_POINTS_INCREMENT); + }; + + /** + * Updates the maximum total number of boxes points that can be defined per draw call, + * and updates the buffers with the new array length sizes. + * @method _setMaxBoxesPoints + * @param {WebGLRenderingContext} ctx + * @param {Number} value The new this._maxBoxesPointsPerDraw value. + * @protected + **/ + p._setMaxBoxesPoints = function (ctx, value) { + this._maxBoxesPointsPerDraw = value; + this._maxBoxesPerDraw = (this._maxBoxesPointsPerDraw / SpriteStage.POINTS_PER_BOX) | 0; + this._maxIndicesPerDraw = this._maxBoxesPerDraw * SpriteStage.INDICES_PER_BOX; + + ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer); + this._vertices = new Float32Array(this._maxBoxesPerDraw * SpriteStage.NUM_VERTEX_PROPERTIES_PER_BOX); + ctx.bufferData(ctx.ARRAY_BUFFER, this._vertices, ctx.DYNAMIC_DRAW); + + // Set up indices for multiple boxes: + this._indices = new Uint16Array(this._maxIndicesPerDraw); // Indices are set once and reused. + for (var i = 0, l = this._indices.length; i < l; i += SpriteStage.INDICES_PER_BOX) { + var j = i * SpriteStage.POINTS_PER_BOX / SpriteStage.INDICES_PER_BOX; + + // Indices for the 2 triangles that make the box: + this._indices[i] = j; + this._indices[i + 1] = j + 1; + this._indices[i + 2] = j + 2; + this._indices[i + 3] = j; + this._indices[i + 4] = j + 2; + this._indices[i + 5] = j + 3; + } + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this._indicesBuffer); + ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, this._indices, ctx.STATIC_DRAW); + }; + + /** + * Sets up a kid's WebGL texture. + * @method _setUpKidTexture + * @param {WebGLRenderingContext} ctx The canvas WebGL context object to draw into. + * @param {Object} kid The list of kids to draw. + * @return {WebGLTexture} + * @protected + **/ + p._setUpKidTexture = function (ctx, kid) { + if (!ctx) { return null; } + + var image, + texture = null; + + if (kid._spritestage_compatibility === 4) { + image = kid.image; + } else if (kid._spritestage_compatibility <= 3 && kid.spriteSheet && kid.spriteSheet._images) { + image = kid.spriteSheet._images[0]; + } + + if (image) { + // Create and use a new texture for this image if it doesn't already have one: + texture = image.__easeljs_texture; + if (!texture) { + texture = image.__easeljs_texture = ctx.createTexture(); + ctx.bindTexture(ctx.TEXTURE_2D, texture); + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + } + } + + return texture; + }; + + /** + * Draw all the kids into the WebGL context. + * @method _drawWebGLKids + * @param {Array} kids The list of kids to draw. + * @param {WebGLRenderingContext} ctx The canvas WebGL context object to draw into. + * @param {Matrix2D} parentMVMatrix The parent's global transformation matrix. + * @protected + **/ + p._drawWebGLKids = function(kids, ctx, parentMVMatrix) { + var kid, mtx, + snapToPixelEnabled = this.snapToPixelEnabled, + image = null, + leftSide = 0, topSide = 0, rightSide = 0, bottomSide = 0, + vertices = this._vertices, + numVertexPropertiesPerBox = SpriteStage.NUM_VERTEX_PROPERTIES_PER_BOX, + maxIndexSize = SpriteStage.MAX_INDEX_SIZE, + maxBoxIndex = this._maxBoxesPerDraw - 1; + + for (var i = 0, l = kids.length; i < l; i++) { + kid = kids[i]; + if (!kid.isVisible()) { continue; } + mtx = kid._matrix; + + // Get the kid's global matrix (relative to the stage): + mtx = (parentMVMatrix ? mtx.copy(parentMVMatrix) : mtx.identity()) + .appendTransform(kid.x, kid.y, kid.scaleX, kid.scaleY, kid.rotation, kid.skewX, kid.skewY, kid.regX, kid.regY); + + // Set default texture coordinates: + var uStart = 0, uEnd = 1, + vStart = 0, vEnd = 1; + + // Define the untransformed bounding box sides and get the kid's image to use for textures: + if (kid._spritestage_compatibility === 4) { + image = kid.image; + + leftSide = 0; + topSide = 0; + rightSide = image.width; + bottomSide = image.height; + } else if (kid._spritestage_compatibility === 2) { + var frame = kid.spriteSheet.getFrame(kid.currentFrame), + rect = frame.rect; + + image = frame.image; + + leftSide = -frame.regX; + topSide = -frame.regY; + rightSide = leftSide + rect.width; + bottomSide = topSide + rect.height; + + uStart = rect.x / image.width; + vStart = rect.y / image.height; + uEnd = uStart + (rect.width / image.width); + vEnd = vStart + (rect.height / image.height); + } else { + image = null; + + // Update BitmapText instances: + if (kid._spritestage_compatibility === 3) { + // TODO: this might change in the future to use a more general approach. + kid._updateText(); + } + } + + // Detect if this kid is a new display branch: + if (!parentMVMatrix && kid._spritestage_compatibility <= 4) { + // Get the texture for this display branch: + var texture = (image || kid.spriteSheet._images[0]).__easeljs_texture; + + // Only use a new texture in the current draw call: + if (texture !== this._drawTexture) { + + // Draw to the GPU if a texture is already in use: + if (this._drawTexture) { + this._drawToGPU(ctx); + } + + this._drawTexture = texture; + + ctx.activeTexture(ctx.TEXTURE0); + ctx.bindTexture(ctx.TEXTURE_2D, texture); + ctx.uniform1i(this._shaderProgram.sampler0uniform, 0); + } + } + + if (image !== null) { + // Set vertices' data: + + var offset = ++this._currentBoxIndex * numVertexPropertiesPerBox, + a = mtx.a, + b = mtx.b, + c = mtx.c, + d = mtx.d, + tx = mtx.tx, + ty = mtx.ty; + + if (snapToPixelEnabled && kid.snapToPixel) { + tx = tx + (tx < 0 ? -0.5 : 0.5) | 0; + ty = ty + (ty < 0 ? -0.5 : 0.5) | 0; + } + + // Positions (calculations taken from Matrix2D.transformPoint): + vertices[offset] = leftSide * a + topSide * c + tx; + vertices[offset + 1] = leftSide * b + topSide * d + ty; + vertices[offset + 5] = leftSide * a + bottomSide * c + tx; + vertices[offset + 6] = leftSide * b + bottomSide * d + ty; + vertices[offset + 10] = rightSide * a + bottomSide * c + tx; + vertices[offset + 11] = rightSide * b + bottomSide * d + ty; + vertices[offset + 15] = rightSide * a + topSide * c + tx; + vertices[offset + 16] = rightSide * b + topSide * d + ty; + + // Texture coordinates: + vertices[offset + 2] = vertices[offset + 7] = uStart; + vertices[offset + 12] = vertices[offset + 17] = uEnd; + vertices[offset + 3] = vertices[offset + 18] = vStart; + vertices[offset + 8] = vertices[offset + 13] = vEnd; + + // Alphas: + vertices[offset + 4] = vertices[offset + 9] = vertices[offset + 14] = vertices[offset + 19] = kid.alpha; + + // Draw to the GPU if the maximum number of boxes per a draw has been reached: + if (this._currentBoxIndex === maxBoxIndex) { + this._drawToGPU(ctx); + + // Set the draw texture again: + this._drawTexture = image.__easeljs_texture; + ctx.activeTexture(ctx.TEXTURE0); + ctx.bindTexture(ctx.TEXTURE_2D, this._drawTexture); + ctx.uniform1i(this._shaderProgram.sampler0uniform, 0); + + // If possible, increase the amount of boxes that can be used per draw call: + if (this._maxBoxesPointsPerDraw < maxIndexSize) { + this._setMaxBoxesPoints(ctx, this._maxBoxesPointsPerDraw + SpriteStage.MAX_BOXES_POINTS_INCREMENT); + maxBoxIndex = this._maxBoxesPerDraw - 1; + } + } + } + + // Draw children: + if (kid.children) { + this._drawWebGLKids(kid.children, ctx, mtx); + maxBoxIndex = this._maxBoxesPerDraw - 1; + } + } + }; + + /** + * Draws all the currently defined boxes to the GPU. + * @method _drawToGPU + * @param {WebGLRenderingContext} ctx The canvas WebGL context object to draw into. + * @protected + **/ + p._drawToGPU = function(ctx) { + var numBoxes = this._currentBoxIndex + 1; + + ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer); + + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this._indicesBuffer); + ctx.uniformMatrix3fv(this._shaderProgram.pMatrixUniform, false, this._projectionMatrix); + ctx.bufferSubData(ctx.ARRAY_BUFFER, 0, this._vertices); + ctx.drawElements(ctx.TRIANGLES, numBoxes * SpriteStage.INDICES_PER_BOX, ctx.UNSIGNED_SHORT, 0); + + // Reset draw vars: + this._currentBoxIndex = -1; + this._drawTexture = null; + }; + +createjs.SpriteStage = SpriteStage; +}()); From bee5d528ec55d4f05efd8bf0d9001acb3ea79d88 Mon Sep 17 00:00:00 2001 From: Aditya Raisinghani Date: Sat, 22 Mar 2014 22:56:41 +0530 Subject: [PATCH 13/30] Made changes to reloadAllCode to reload only the team's code. --- app/views/play/level/tome/tome_view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/play/level/tome/tome_view.coffee b/app/views/play/level/tome/tome_view.coffee index 65af01739..68ca029bf 100644 --- a/app/views/play/level/tome/tome_view.coffee +++ b/app/views/play/level/tome/tome_view.coffee @@ -213,7 +213,7 @@ module.exports = class TomeView extends View @spellPaletteView.toggleControls {}, spell.view.controlsEnabled # TODO: know when palette should have been disabled but didn't exist reloadAllCode: -> - spell.view.reloadCode false for spellKey, spell of @spells + spell.view.reloadCode false for spellKey, spell of @spells when spell.team is me.team Backbone.Mediator.publish 'tome:cast-spells', spells: @spells destroy: -> From 5e311cdefaa8242eec2ab8a3a90df15ca045875e Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sat, 22 Mar 2014 10:54:35 -0700 Subject: [PATCH 14/30] Fixed css for IE warnings. --- app/styles/application.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/styles/application.sass b/app/styles/application.sass index fa771fbe6..893c9dfd3 100644 --- a/app/styles/application.sass +++ b/app/styles/application.sass @@ -29,7 +29,7 @@ h1 left: -50% z-index: 1 -body +html .lt-ie7, .lt-ie8, .lt-ie9, .lt-ie10 display: none &.lt-ie7 .lt-ie7 From c3b745b271f0dbf663693c7bf50c6115cb1d8c49 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sat, 22 Mar 2014 11:30:56 -0700 Subject: [PATCH 15/30] Added Catalan language file --- app/locale/ar.coffee | 21 +- app/locale/bg.coffee | 21 +- app/locale/ca.coffee | 572 ++++++++++++++++++++++++++++++++++ app/locale/cs.coffee | 21 +- app/locale/da.coffee | 19 +- app/locale/de.coffee | 19 +- app/locale/el.coffee | 21 +- app/locale/en-AU.coffee | 19 +- app/locale/en-GB.coffee | 19 +- app/locale/en-US.coffee | 19 +- app/locale/es-419.coffee | 19 +- app/locale/es-ES.coffee | 21 +- app/locale/es.coffee | 33 +- app/locale/fa.coffee | 21 +- app/locale/fi.coffee | 21 +- app/locale/fr.coffee | 23 +- app/locale/he.coffee | 19 +- app/locale/hi.coffee | 21 +- app/locale/hu.coffee | 21 +- app/locale/id.coffee | 21 +- app/locale/it.coffee | 19 +- app/locale/ja.coffee | 21 +- app/locale/ko.coffee | 22 +- app/locale/lt.coffee | 21 +- app/locale/ms.coffee | 31 +- app/locale/nb.coffee | 21 +- app/locale/nl.coffee | 17 + app/locale/nn.coffee | 21 +- app/locale/no.coffee | 21 +- app/locale/pl.coffee | 17 + app/locale/pt-BR.coffee | 19 +- app/locale/pt-PT.coffee | 25 +- app/locale/pt.coffee | 21 +- app/locale/ro.coffee | 19 +- app/locale/ru.coffee | 17 + app/locale/sk.coffee | 21 +- app/locale/sl.coffee | 21 +- app/locale/sr.coffee | 21 +- app/locale/sv.coffee | 19 +- app/locale/th.coffee | 21 +- app/locale/tr.coffee | 21 +- app/locale/uk.coffee | 21 +- app/locale/ur.coffee | 21 +- app/locale/vi.coffee | 55 ++-- app/locale/zh-HANS.coffee | 21 +- app/locale/zh-HANT.coffee | 21 +- app/locale/zh.coffee | 23 +- scripts/copy-i18n-tags.coffee | 4 +- 48 files changed, 1463 insertions(+), 110 deletions(-) create mode 100644 app/locale/ca.coffee diff --git a/app/locale/ar.coffee b/app/locale/ar.coffee index a60615c42..0e02c672a 100644 --- a/app/locale/ar.coffee +++ b/app/locale/ar.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/bg.coffee b/app/locale/bg.coffee index 4c738a135..28dcc9ba5 100644 --- a/app/locale/bg.coffee +++ b/app/locale/bg.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "български език", englishDescri # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "български език", englishDescri # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "български език", englishDescri # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "български език", englishDescri # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "български език", englishDescri # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/ca.coffee b/app/locale/ca.coffee new file mode 100644 index 000000000..3a251f1e4 --- /dev/null +++ b/app/locale/ca.coffee @@ -0,0 +1,572 @@ +module.exports = nativeDescription: "Català", englishDescription: "Catalan", translation: +# common: +# loading: "Loading..." +# saving: "Saving..." +# sending: "Sending..." +# cancel: "Cancel" +# save: "Save" +# delay_1_sec: "1 second" +# delay_3_sec: "3 seconds" +# delay_5_sec: "5 seconds" +# manual: "Manual" +# fork: "Fork" +# play: "Play" + +# modal: +# close: "Close" +# okay: "Okay" + +# not_found: +# page_not_found: "Page not found" + +# nav: +# play: "Levels" +# editor: "Editor" +# blog: "Blog" +# forum: "Forum" +# admin: "Admin" +# home: "Home" +# contribute: "Contribute" +# legal: "Legal" +# about: "About" +# contact: "Contact" +# twitter_follow: "Follow" +# 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: "Create Account" +# log_in: "Log In" +# log_out: "Log Out" +# recover: "recover account" + +# recover: +# recover_account_title: "Recover Account" +# send_password: "Send Recovery Password" + +# signup: +# create_account_title: "Create Account to Save Progress" +# description: "It's free. Just need a couple things and you'll be good to go:" +# email_announcements: "Receive announcements by email" +# coppa: "13+ or non-USA " +# coppa_why: "(Why?)" +# creating: "Creating Account..." +# sign_up: "Sign Up" +# log_in: "log in with password" + +# home: +# slogan: "Learn to Code JavaScript by Playing a Game" +# no_ie: "CodeCombat does not run in Internet Explorer 9 or older. Sorry!" +# no_mobile: "CodeCombat wasn't designed for mobile devices and may not work!" +# play: "Play" +# 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" + +# play: +# choose_your_level: "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: "Difficulty: " +# play_as: "Play As" +# spectate: "Spectate" + +# contact: +# contact_us: "Contact CodeCombat" +# 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: "our forum" +# forum_suffix: " instead." +# send: "Send Feedback" + + diplomat_suggestion: +# title: "Help translate CodeCombat!" +# sub_heading: "We need your language skills." + pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Catalan, 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 Catalan." + missing_translations: "Until we can translate everything into Catalan, you'll see English when Catalan isn't available." +# learn_more: "Learn more about being a Diplomat" +# subscribe_as_diplomat: "Subscribe as a Diplomat" + +# wizard_settings: +# title: "Wizard Settings" +# customize_avatar: "Customize Your Avatar" +# clothes: "Clothes" +# trim: "Trim" +# cloud: "Cloud" +# spell: "Spell" +# boots: "Boots" +# hue: "Hue" +# saturation: "Saturation" +# lightness: "Lightness" + +# account_settings: +# title: "Account Settings" +# not_logged_in: "Log in or create an account to change your settings." +# autosave: "Changes Save Automatically" +# me_tab: "Me" +# picture_tab: "Picture" +# wizard_tab: "Wizard" +# password_tab: "Password" +# emails_tab: "Emails" +# admin: "Admin" +# gravatar_select: "Select which Gravatar photo to use" +# gravatar_add_photos: "Add thumbnails and photos to a Gravatar account for your email to choose an image." +# gravatar_add_more_photos: "Add more photos to your Gravatar account to access them here." +# wizard_color: "Wizard Clothes Color" +# new_password: "New Password" +# new_password_verify: "Verify" +# email_subscriptions: "Email Subscriptions" +# email_announcements: "Announcements" +# email_notifications: "Notifications" +# email_notifications_description: "Get periodic notifications for your account." +# email_announcements_description: "Get emails on the latest news and developments at CodeCombat." +# contributor_emails: "Contributor Class Emails" +# contribute_prefix: "We're looking for people to join our party! Check out the " +# contribute_page: "contribute page" +# contribute_suffix: " to find out more." +# email_toggle: "Toggle All" +# error_saving: "Error Saving" +# saved: "Changes Saved" +# password_mismatch: "Password does not match." + +# account_profile: +# edit_settings: "Edit Settings" +# profile_for_prefix: "Profile for " +# profile_for_suffix: "" +# profile: "Profile" +# user_not_found: "No user found. Check the URL?" +# gravatar_not_found_mine: "We couldn't find your profile associated with:" +# gravatar_not_found_email_suffix: "." +# gravatar_signup_prefix: "Sign up at " +# gravatar_signup_suffix: " to get set up!" +# gravatar_not_found_other: "Alas, there's no profile associated with this person's email address." +# gravatar_contact: "Contact" +# gravatar_websites: "Websites" +# gravatar_accounts: "As Seen On" +# gravatar_profile_link: "Full Gravatar Profile" + +# play_level: +# level_load_error: "Level could not be loaded: " +# done: "Done" +# grid: "Grid" +# customize_wizard: "Customize Wizard" +# home: "Home" +# guide: "Guide" +# multiplayer: "Multiplayer" +# restart: "Restart" +# goals: "Goals" +# 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_rank_my_game: "Rank My Game" +# victory_ranking_game: "Submitting..." +# 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™!" +# multiplayer_title: "Multiplayer Settings" +# 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!" +# 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_autocast_delay: "Autocast Delay" +# 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)" +# editor_config: "Editor Config" +# editor_config_title: "Editor Configuration" +# 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_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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " + +# admin: +# av_title: "Admin Views" +# av_entities_sub_title: "Entities" +# av_entities_users_url: "Users" +# av_entities_active_instances_url: "Active Instances" +# 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" + +# editor: +# main_title: "CodeCombat Editors" +# main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" +# article_title: "Article Editor" +# article_description: "Write articles that give players overviews of programming concepts which can be used across a variety of levels and campaigns." +# thang_title: "Thang Editor" +# thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." +# level_title: "Level Editor" +# level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" +# security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " +# contact_us: "contact us!" +# hipchat_prefix: "You can also find us in our" +# hipchat_url: "HipChat room." +# revert: "Revert" +# revert_models: "Revert Models" +# 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_conditions: "Starting Conditions" +# level_tab_thangs_add: "Add Thangs" +# 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" +# article_search_title: "Search Articles Here" +# thang_search_title: "Search Thang Types Here" +# level_search_title: "Search Levels Here" + +# article: +# edit_btn_preview: "Preview" +# edit_article_title: "Edit Article" + +# general: +# and: "and" +# name: "Name" +# body: "Body" +# version: "Version" +# commit_msg: "Commit Message" +# history: "History" +# version_history_for: "Version History for: " +# result: "Result" +# results: "Results" +# description: "Description" +# or: "or" +# email: "Email" +# password: "Password" +# message: "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" + +# 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." +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" + +# 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, and Jeremy" +# alert_account_message_intro: "Hey there!" +# alert_account_message_pref: "To subscribe for class emails, you'll need to " +# alert_account_message_suf: "first." +# alert_account_message_create_url: "create an account" +# 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." +# counselor_summary: "None of the above roles fit what you are interested in? Do not worry, we are on the lookout for anybody who wants a hand in the development of CodeCombat! If you are interested in teaching, game development, open source management, or anything else that you think will be relevant to us, then this class is for you." +# counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." +# counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." +# counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." +# counselor_attribute_2: "A little bit of free time!" +# counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." +# more_about_counselor: "Learn More About Becoming a Counselor" +# 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)" +# counselor_title: "Counselor" +# counselor_title_description: "(Expert/Teacher)" + +# 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:" +# 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" +# 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" +# 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" + +# multiplayer_launch: +# introducing_dungeon_arena: "Introducing Dungeon Arena" +# new_way: "March 17, 2014: The new way to compete with code." +# to_battle: "To Battle, Developers!" +# modern_day_sorcerer: "You know how to code? That's badass. You're a modern-day sorcerer! Isn't about time that you used your magic coding powers to command your minions in epic combat? And we're not talking robots here." +# arenas_are_here: "CodeCombat head-to-head multiplayer arenas are here." +# ladder_explanation: "Choose your heroes, enchant your human or ogre armies, and climb your way over defeated fellow Wizards to reach the top of the ladders–then challenge your friends in our glorious, asynchronous multiplayer coding arenas. If you're feeling creative, you can even" +# fork_our_arenas: "fork our arenas" +# create_worlds: "and create your own worlds." +# javascript_rusty: "JavaScript a bit rusty? Don't worry; there's a" +# tutorial: "tutorial" +# new_to_programming: ". New to programming? Hit our beginner campaign to skill up." +# so_ready: "I Am So Ready for This" diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee index 8d553c2aa..afece81eb 100644 --- a/app/locale/cs.coffee +++ b/app/locale/cs.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr campaign_player_created: "Uživatelsky vytvořené úrovně" campaign_player_created_description: "...ve kterých bojujete proti kreativitě ostatních Zdatných Kouzelníků." level_difficulty: "Obtížnost: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Administrátorský pohled" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr av_other_debug_base_url: "Base (pro debugování base.jade)" u_title: "Seznam uživatelů" lg_title: "Poslední hry" +# clas: "CLAs" editor: main_title: "Editory CodeCombatu" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr nick_description: "Programátorský kouzelník, excentrický motivační mág i experimentátor. Nick by mohl dělat de-facto cokoliv, ale zvolil si vytvořit CodeCombat." jeremy_description: "Mistr zákaznické podpory, tester použitelnosti a organizátor komunity. Je velmi pravděpodobné, že jste si spolu již psali." michael_description: "Programátor, systémový administrátor a král podsvětí technického zázemí. Michael udržuje naše servery online." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Licence" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/da.coffee b/app/locale/da.coffee index 18a0d4789..2e1ef5ee6 100644 --- a/app/locale/da.coffee +++ b/app/locale/da.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # av_other_debug_base_url: "Base (for debugging base.jade)" u_title: "Brugerliste" lg_title: "Seneste spil" +# clas: "CLAs" editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/de.coffee b/app/locale/de.coffee index 8b453fa9f..eed6ea34a 100644 --- a/app/locale/de.coffee +++ b/app/locale/de.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra editor_config_indentguides_description: "Zeigt vertikale Linien an um Einrückungen besser zu sehen." # editor_config_behaviors_label: "Smart Behaviors" # editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Administrator Übersicht" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra # av_other_debug_base_url: "Base (for debugging base.jade)" u_title: "Benutzerliste" lg_title: "Letzte Spiele" +# clas: "CLAs" editor: main_title: "CodeCombat Editoren" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Rechtliches" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/el.coffee b/app/locale/el.coffee index 7c91855b4..f904eee40 100644 --- a/app/locale/el.coffee +++ b/app/locale/el.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # 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 " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/en-AU.coffee b/app/locale/en-AU.coffee index 6b5fc38d6..c95dafa63 100644 --- a/app/locale/en-AU.coffee +++ b/app/locale/en-AU.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/en-GB.coffee b/app/locale/en-GB.coffee index 650e626e2..d7a2b5005 100644 --- a/app/locale/en-GB.coffee +++ b/app/locale/en-GB.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/en-US.coffee b/app/locale/en-US.coffee index c3498ac88..50500b74a 100644 --- a/app/locale/en-US.coffee +++ b/app/locale/en-US.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/es-419.coffee b/app/locale/es-419.coffee index 42e6f5714..366324207 100644 --- a/app/locale/es-419.coffee +++ b/app/locale/es-419.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee index 1b6c2f4bd..cfb50ee76 100644 --- a/app/locale/es-ES.coffee +++ b/app/locale/es-ES.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis campaign_player_created: "Creaciones de los Jugadores" campaign_player_created_description: "... en las que luchas contra la creatividad de tus compañeros Magos Artesanos." level_difficulty: "Dificultad: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # av_other_debug_base_url: "Base (for debugging base.jade)" u_title: "Lista de Usuarios" lg_title: "Últimos Juegos" +# clas: "CLAs" editor: main_title: "Editores de CodeCombat" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis nick_description: "Mago de la programación, hechicero excéntrico de la motivación y experimentador del revés. Nick pudo haber hecho cualquier cosa y eligió desarrollar CodeCombat." jeremy_description: "Mago de la atención al cliente, tester de usabilidad y organizador de la comunidad; es probable que ya hayas hablado con Jeremy." michael_description: "Programador, administrador de sistemas y prodigio técnico, Michael es el encargado de mantener nuestros servidores en línea." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/es.coffee b/app/locale/es.coffee index cf32e9db3..ad8e19a09 100644 --- a/app/locale/es.coffee +++ b/app/locale/es.coffee @@ -225,8 +225,22 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " -# admin: + admin: # av_title: "Admin Views" # av_entities_sub_title: "Entities" av_entities_users_url: "Usuarios" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # av_other_debug_base_url: "Base (for debugging base.jade)" u_title: "Lista de usuario" lg_title: "Últimos juegos" +# clas: "CLAs" editor: # main_title: "CodeCombat Editors" @@ -282,7 +297,7 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # thang_search_title: "Search Thang Types Here" # level_search_title: "Search Levels Here" -# article: + article: edit_btn_preview: "Previsualizar" edit_article_title: "Editar artículo" @@ -314,9 +329,9 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t medium: "Medio" hard: "Difíficl" -# about: -# who_is_codecombat: "¿Quién es CodeCombat?" -# why_codecombat: "¿Por qué CodeCombat?" + 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." @@ -335,7 +350,7 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -398,7 +413,7 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # 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: + contribute: # page_title: "Contributing" # character_classes_title: "Character Classes" # introduction_desc_intro: "We have high hopes for CodeCombat." @@ -508,13 +523,15 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # counselor_title: "Counselor" # counselor_title_description: "(Expert/Teacher)" -# ladder: + 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/fa.coffee b/app/locale/fa.coffee index a5f9ad1fc..e5ee01d10 100644 --- a/app/locale/fa.coffee +++ b/app/locale/fa.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", campaign_player_created: "ایجاد بازیکن" campaign_player_created_description: "... جایی که در مقابل خلاقیت نیرو هاتون قرار میگیرید جادوگران آرتیزان." level_difficulty: "سختی: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/fi.coffee b/app/locale/fi.coffee index b839a8965..15c82cfdf 100644 --- a/app/locale/fi.coffee +++ b/app/locale/fi.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee index 667f81052..0b578588e 100644 --- a/app/locale/fr.coffee +++ b/app/locale/fr.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "français", englishDescription: "French", t editor_config_indentguides_description: "Affiche des guides verticaux qui permettent de visualiser l'indentation." editor_config_behaviors_label: "Auto-complétion" editor_config_behaviors_description: "Ferme automatiquement les accolades, parenthèses, et chaînes de caractères." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Vues d'administrateurs" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t av_other_debug_base_url: "Base (pour debugger base.jade)" u_title: "Liste des utilisateurs" lg_title: "Dernières parties" +# clas: "CLAs" editor: main_title: "Éditeurs CodeCombat" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t nick_description: "Assistant programmeur, mage à la motivation excentrique, et bidouilleur de l'extrême. Nick peut faire n'importe quoi mais il a choisi CodeCombat." jeremy_description: "Mage de l'assistance client, testeur de maniabilité, et community manager; vous avez probablement déjà parlé avec Jeremy." michael_description: "Programmeur, administrateur réseau, et l'enfant prodige du premier cycle, Michael est la personne qui maintient nos serveurs en ligne." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Légal" @@ -509,12 +524,14 @@ module.exports = nativeDescription: "français", englishDescription: "French", t counselor_title_description: "(Expert/Professeur)" ladder: -# please_login: "Identifie toi avant de jouer à un ladder game." + please_login: "Identifie toi avant de jouer à un ladder game." my_matches: "Mes Matchs" simulate: "Simuler" simulation_explanation: "En simulant une partie, tu peux classer ton rang plus rapidement!" simulate_games: "Simuler une Partie!" simulate_all: "REINITIALISER ET SIMULER DES PARTIES" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Classement" battle_as: "Combattre comme " summary_your: "Vos " @@ -540,7 +557,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t warmup: "Préchauffe" vs: "VS" -# multiplayer_launch: + multiplayer_launch: # introducing_dungeon_arena: "Introducing Dungeon Arena" # new_way: "March 17, 2014: The new way to compete with code." # to_battle: "To Battle, Developers!" diff --git a/app/locale/he.coffee b/app/locale/he.coffee index 20f0bca44..d16007378 100644 --- a/app/locale/he.coffee +++ b/app/locale/he.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee index 13df8c201..c36dcbacc 100644 --- a/app/locale/hi.coffee +++ b/app/locale/hi.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee index 35f3584a4..0842ea53b 100644 --- a/app/locale/hu.coffee +++ b/app/locale/hu.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t campaign_player_created: "Játékosok pályái" campaign_player_created_description: "...melyekben Művészi Varázsló társaid ellen kűzdhetsz." level_difficulty: "Nehézség: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" editor: main_title: "CodeCombat szerkesztők" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/id.coffee b/app/locale/id.coffee index 8799a1ec1..8c04df18f 100644 --- a/app/locale/id.coffee +++ b/app/locale/id.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/it.coffee b/app/locale/it.coffee index 5d2c14f17..c94ad20d0 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Vista amministratore" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t av_other_debug_base_url: "Base (for debugging base.jade)" u_title: "Lista utenti" lg_title: "Ultime partite" +# clas: "CLAs" editor: main_title: "Editor di CodeCombat" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Questioni legali" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee index ba6a21dd5..e43327880 100644 --- a/app/locale/ja.coffee +++ b/app/locale/ja.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # 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 " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "管理画面" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee index ce567d414..09e598365 100644 --- a/app/locale/ko.coffee +++ b/app/locale/ko.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t editor_config_indentguides_description: "들여쓰기 확인위해 세로줄 표시하기." editor_config_behaviors_label: "자동 기능" editor_config_behaviors_description: "괄호, 인용부호, 따옴표 자동 완성." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "관리자 뷰" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t av_other_debug_base_url: "베이스 (base.jade 디버깅)" u_title: "유저 목록" lg_title: "가장 최근 게임" +# clas: "CLAs" editor: main_title: "코드 컴뱃 에디터들" @@ -244,8 +259,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t thang_title: "Thang 에디터" thang_description: "유닛들, 기본적인 인공지능, 그래픽과 오디오등을 직접 빌드하세요. 현재는 백터 그래픽으로 추출된 플래시파일만 임폴트 가능합니다." level_title: "레벨 에디터" - level_description: "스크립팅, 오디오 업로드, 모든 레벨을 생성하기 위한 사용자 정의 로직등 우리가 사용하는 모든 것들을 구축하는 것을 위한 툴들을 포함합니다. -" + level_description: "스크립팅, 오디오 업로드, 모든 레벨을 생성하기 위한 사용자 정의 로직등 우리가 사용하는 모든 것들을 구축하는 것을 위한 툴들을 포함합니다." security_notice: "이러한 에디터들의 중요한 특징들은 현재 대부분 기본적으로 제공되지 않습니다. 조만간 이런 시스템들의 안정성을 업그레이트 한후에, 이러한 기능들이 제공될 것입니다." contact_us: "연락하기!" hipchat_prefix: "당신은 또한 우리를 여기에서 찾을 수 있습니다 : " @@ -336,7 +350,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t nick_description: "프로그래밍 마법사, 별난 자극의 마술사, 거꾸로 생각하는것을 좋아하는 실험가. Nick은 뭐든지 할수있는 남자입니다. 그 뭐든지 중에 코드 컴뱃을 선택했죠. " jeremy_description: "고객 지원 마법사, 사용성 테스터, 커뮤니티 오거나이저; 당신은 아마 이미 Jeremy랑 이야기 했을거에요." michael_description: "프로그래머, 시스템 관리자, 기술 신동(대학생이래요),Michael 은 우리 서버를 계속 무결점상태로 유지시켜주는 사람입니다." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -516,6 +530,8 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/lt.coffee b/app/locale/lt.coffee index 42d5d7dd0..ab7ef9ee8 100644 --- a/app/locale/lt.coffee +++ b/app/locale/lt.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/ms.coffee b/app/locale/ms.coffee index bf8046901..9b1210c31 100644 --- a/app/locale/ms.coffee +++ b/app/locale/ms.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -98,7 +98,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # contribute_suffix: "!" forum_prefix: "Untuk perkara lain, sila cuba " forum_page: "forum kami" -# forum_suffix: "." +# forum_suffix: " instead." send: "Hantar Maklumbalas" diplomat_suggestion: @@ -164,7 +164,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # gravatar_not_found_other: "Alas, there's no profile associated with this person's email address." gravatar_contact: "Hubungi" gravatar_websites: "Lelaman" -# gravatar_accounts: "Juga didapati di" + gravatar_accounts: "Juga didapati di" gravatar_profile_link: "Profil Penuh Gravatar" # play_level: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -308,7 +323,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # rank: "Rank" score: "Mata" win: "Menang" -# loss: "Kalah" + loss: "Kalah" tie: "Seri" # easy: "Easy" # medium: "Medium" @@ -324,10 +339,10 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa why_paragraph_2: "Mahu belajar untuk membina kod? Anda tidak perlu membaca dan belajar. Anda perlu menaip kod yang banyak dan bersuka-suka dengan masa yang terluang." why_paragraph_3_prefix: "Itulah semua tentang pengaturcaraan. Ia harus membuat anda gembira dan rasa berpuas hati. Tidak seperti" why_paragraph_3_italic: "yay satu badge" -# why_paragraph_3_center: "tapi bersukaria seperti" + why_paragraph_3_center: "tapi bersukaria seperti" why_paragraph_3_italic_caps: "TIDAK MAK SAYA PERLU HABISKAN LEVEL!" why_paragraph_3_suffix: "Itulah kenapa CodeCombat adalah permainan multiplayer, tapi bukan sebuah khursus dibuat sebagai permainan. Kami tidak akan berhenti sehingga kamu tidak akan--tetapi buat masa kini, itulah perkara yang baik." -# why_paragraph_4: "Jika kamu mahu berasa ketagih terhadap sesuatu permainan komputer, jadilah ketagih kepada permainan ini dan jadilah seorang pakar dalam zaman teknologi terkini." + why_paragraph_4: "Jika kamu mahu berasa ketagih terhadap sesuatu permainan komputer, jadilah ketagih kepada permainan ini dan jadilah seorang pakar dalam zaman teknologi terkini." why_ending: "Dan ia adalah percuma! " why_ending_url: "Mulalah bermain sekarang!" # george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/nb.coffee b/app/locale/nb.coffee index 2e4fd394a..f359c043b 100644 --- a/app/locale/nb.coffee +++ b/app/locale/nb.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg campaign_player_created: "Spiller-Lagde" campaign_player_created_description: "... hvor du kjemper mot kreativiteten til en av dine medspillende Artisan Trollmenn." level_difficulty: "Vanskelighetsgrad: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/nl.coffee b/app/locale/nl.coffee index 090bc7969..786ac8d6c 100644 --- a/app/locale/nl.coffee +++ b/app/locale/nl.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t editor_config_indentguides_description: "Toon verticale hulplijnen om de zichtbaarheid te verbeteren." editor_config_behaviors_label: "Slim gedrag" editor_config_behaviors_description: "Auto-aanvulling (gekrulde) haakjes en aanhalingstekens." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Administrator panels" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t av_other_debug_base_url: "Base (om base.jade te debuggen)" u_title: "Gebruikerslijst" lg_title: "Laatste Spelletjes" +# clas: "CLAs" editor: main_title: "CodeCombat Editors" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t 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: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Leaderboard" battle_as: "Vecht als " summary_your: "Jouw " diff --git a/app/locale/nn.coffee b/app/locale/nn.coffee index 7a0fced5c..fff426d8d 100644 --- a/app/locale/nn.coffee +++ b/app/locale/nn.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/no.coffee b/app/locale/no.coffee index b1df6cf90..721b4cf57 100644 --- a/app/locale/no.coffee +++ b/app/locale/no.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr campaign_player_created: "Spiller-Lagde" campaign_player_created_description: "... hvor du kjemper mot kreativiteten til en av dine medspillende Artisan Trollmenn." level_difficulty: "Vanskelighetsgrad: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/pl.coffee b/app/locale/pl.coffee index 470f7f3c7..5b2498be7 100644 --- a/app/locale/pl.coffee +++ b/app/locale/pl.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish editor_config_indentguides_description: "Wyświetla pionowe linie, by lepiej zaznaczyć wcięcia." editor_config_behaviors_label: "Inteligentne zachowania" editor_config_behaviors_description: "Autouzupełnianie nawiasów, klamer i cudzysłowów." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Panel administracyjny" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish av_other_debug_base_url: "Baza (do debuggingu base.jade)" u_title: "Lista użytkowników" lg_title: "Ostatnie gry" +# clas: "CLAs" editor: main_title: "Edytory CodeCombat" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish simulation_explanation: "Symulując gry możesz szybciej uzyskać ocenę swojej gry!" simulate_games: "Symuluj gry!" simulate_all: "RESETUJ I SYMULUJ GRY" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Tabela rankingowa" battle_as: "Walcz jako " summary_your: "Twój " diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee index 3f58c9a26..764aa3c48 100644 --- a/app/locale/pt-BR.coffee +++ b/app/locale/pt-BR.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: editor_config_indentguides_description: "Mostrar linhas verticais para ver a identação melhor." editor_config_behaviors_label: "Comportamentos Inteligentes" editor_config_behaviors_description: "Completar automaticamente colchetes, chaves e aspas." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Visualização de Administrador" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: av_other_debug_base_url: "Base (para debugar base.jade)" u_title: "Lista de Usuários" lg_title: "Últimos Jogos" +# clas: "CLAs" editor: main_title: "Editores do CodeCombat" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: nick_description: "Mago da programação, feiticeiro da motivação excêntrica e experimentador doido. Nick pode fazer qualquer coisa e escolheu desenvolver o CodeCombat." jeremy_description: "Mago em suporte ao consumidor, testador de usabilidade, e organizador da comunidade; você provavelmente já falou com o Jeremy." michael_description: "Programador, administrador de sistemas, e um técnico prodígio não graduado, Michael é a pessoa que mantém os servidores funcionando." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Jurídico" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: simulation_explanation: "Por simular partidas você pode classificar seu jogo mais rápido!" simulate_games: "Simular Partidas!" simulate_all: "RESETAR E SIMULAR PARTIDAS" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Tabela de Classificação" battle_as: "Lutar como " summary_your: "Seus " diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee index 791328af2..1a02a40b8 100644 --- a/app/locale/pt-PT.coffee +++ b/app/locale/pt-PT.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Visualizações de Admin" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P av_other_debug_base_url: "Base (para fazer debug base.jade)" u_title: "Lista de Utilizadores" lg_title: "Últimos Jogos" +# clas: "CLAs" editor: main_title: "Editores para CodeCombat" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -508,13 +523,15 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P counselor_title: "Counselor" counselor_title_description: "(Expert/ Professor)" -# ladder: + ladder: # please_login: "Please log in first before playing a ladder game." my_matches: "Os meus jogos" simulate: "Simular" # simulation_explanation: "By simulating games you can get your game ranked faster!" - simulate_games: "Simular Jogos!" +# simulate_games: "Simulate Games!" # simulate_all: "RESET AND SIMULATE GAMES" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " @@ -540,7 +557,7 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P warmup: "Aquecimento" vs: "VS" -# multiplayer_launch: + multiplayer_launch: introducing_dungeon_arena: "Introduzindo a Dungeon Arena" new_way: "17 de Março de 2014: Uma nova forma de competir com código." to_battle: "Às armas, Programadores!" diff --git a/app/locale/pt.coffee b/app/locale/pt.coffee index feb67d479..b6c8c23d5 100644 --- a/app/locale/pt.coffee +++ b/app/locale/pt.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues 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 " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee index bfe319854..e5ad7fadd 100644 --- a/app/locale/ro.coffee +++ b/app/locale/ro.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Admin vede" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman av_other_debug_base_url: "Base (pentru debugging base.jade)" u_title: "Listă utilizatori" lg_title: "Ultimele jocuri" +# clas: "CLAs" editor: main_title: "Editori CodeCombat" @@ -335,7 +350,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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Aspecte Legale" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman simulation_explanation: "Simulând jocuri poți afla poziția în clasament a jocului tău mai repede!" simulate_games: "Simulează Jocuri!" simulate_all: "RESETEAZĂ ȘI SIMULEAZĂ JOCURI" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Clasament" battle_as: "Luptă ca " summary_your: "Al tău " diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee index 39e6055ee..3b5dc211c 100644 --- a/app/locale/ru.coffee +++ b/app/locale/ru.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi editor_config_indentguides_description: "Отображение вертикальных линий для лучшего обзора отступов." editor_config_behaviors_label: "Умное поведение" editor_config_behaviors_description: "Автозавершать квадратные, фигурные скобки и кавычки." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Админ панель" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi av_other_debug_base_url: "База (для отладки base.jade)" u_title: "Список пользователей" lg_title: "Последние игры" +# clas: "CLAs" editor: main_title: "Редакторы CodeCombat" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi simulation_explanation: "Симулированием игр вы сможете быстрее получить оценку игры!" simulate_games: "Симулировать игры!" simulate_all: "СБРОСИТЬ И СИМУЛИРОВАТЬ ИГРЫ" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Таблица лидеров" battle_as: "Сразиться за " summary_your: "Ваши " diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee index 72229679f..13016ed7c 100644 --- a/app/locale/sk.coffee +++ b/app/locale/sk.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", campaign_player_created: "Hráčmi vytvorené levely" campaign_player_created_description: "... v ktorých sa popasujete s kreativitou svojich súdruhov kúzelníkov." level_difficulty: "Obtiažnosť." -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/sl.coffee b/app/locale/sl.coffee index 89adb77ce..8fd2cc986 100644 --- a/app/locale/sl.coffee +++ b/app/locale/sl.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee index acb613416..fcb9e48e1 100644 --- a/app/locale/sr.coffee +++ b/app/locale/sr.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian campaign_player_created: "Направљено од стране играча" campaign_player_created_description: "... у којима се бориш против креативности својих колега." level_difficulty: "Тежина: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/sv.coffee b/app/locale/sv.coffee index a78a31df5..d29389404 100644 --- a/app/locale/sv.coffee +++ b/app/locale/sv.coffee @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr editor_config_indentguides_description: "Visar vertikala linjer för att kunna se indentering bättre." editor_config_behaviors_label: "Smart beteende" editor_config_behaviors_description: "Avsluta automatiskt hakparenteser, parenteser, och citat." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Administratörsvyer" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr av_other_debug_base_url: "Base (för avlusning av base.jade)" u_title: "Användarlista" lg_title: "Senaste matcher" +# clas: "CLAs" editor: main_title: "CodeCombatredigerare" @@ -441,7 +456,7 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr more_about_artisan: "Lär dig mer om att bli en hantverkare" artisan_subscribe_desc: "Få mail om nivåredigeraruppdateringar och tillkännagivanden" adventurer_summary: "Låt oss vara tydliga med din roll: du är tanken. Du kommer att ta stor skada. Vi behöver människor som kan testa splitternya nivåer och hjälpa till att identifiera hur man kan göra saker bättre. Smärtan kommer att vara enorm; att göra bra spel är en lång process och ingen gör rätt första gången. Om du kan härda ut och tål mycket stryk är det här klassen för dig." -# adventurer_introduction: "Låt oss vara tydliga med din roll: du är tanken. Du kommer att ta stor skada. Vi behöver människor som kan testa splitternya nivåer och hjälpa till att identifiera hur man kan göra saker bättre. Smärtan kommer att vara enorm; att göra bra spel är en lång process och ingen gör rätt första gången. Om du kan härda ut och tål mycket stryk är det här kanske klassen för dig." + adventurer_introduction: "Låt oss vara tydliga med din roll: du är tanken. Du kommer att ta stor skada. Vi behöver människor som kan testa splitternya nivåer och hjälpa till att identifiera hur man kan göra saker bättre. Smärtan kommer att vara enorm; att göra bra spel är en lång process och ingen gör rätt första gången. Om du kan härda ut och tål mycket stryk är det här klassen för dig." adventurer_attribute_1: "En törst efter att lära sig. Du vill lära dig att koda och vi vill lära dig att koda. Du kommer förmodligen att vara den som lär ut mest i det här fallet, dock." adventurer_attribute_2: "Karismatisk. Var varsammen tydlig med vad som behöver förbättras, och erbjud förslag på hur förbättringar kan ske." adventurer_join_pref: "Antingen träffar (eller rekryterar!) du en hantverkare och jobbar med denna, eller så kryssar du i rutan nedanför för att få mail när det finns nya nivåer att testa. Vi kommer också att anslå nivåer som behöver granskas på nätverk som" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr simulation_explanation: "Genom att simulera matcher kan du få dina matcher rankade fortare." simulate_games: "Simulera matcher!" simulate_all: "ÅTERSTÄLL OCH SIMULERA MATCHER" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" leaderboard: "Resultattavla" battle_as: "Kämpa som " summary_your: "Dina " diff --git a/app/locale/th.coffee b/app/locale/th.coffee index 42f447444..da3708016 100644 --- a/app/locale/th.coffee +++ b/app/locale/th.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/tr.coffee b/app/locale/tr.coffee index 36f8f3b50..bfe88acd2 100644 --- a/app/locale/tr.coffee +++ b/app/locale/tr.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t 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..." level_difficulty: "Zorluk: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "Yönetici Görünümleri" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t av_other_debug_base_url: "Temel (base.jade hata kontrolü)" u_title: "Kullanıcı Listesi" lg_title: "Yeni Oyunlar" +# clas: "CLAs" editor: main_title: "CodeCombat Düzenleyici" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t nick_description: "Programlama sihirbazı, tuhaf motivasyon büyücü ve tersine mühendis. Nick her şeyden anlar ve şu anda CodeCombat'i inşa etmekle meşgul." jeremy_description: "Müşteri hizmetleri büyücüsü, kullanılabilirlik test edicisi ve topluluk örgütleyici; muhtemelen Jeremy ile konuşmuşluğunuz vardır." michael_description: "Programcı, sistem yöneticisi, halihazırda üniversite okuyan teknik-harika-çocuk. Michael sunucularımızı ayakta tutan adamın ta kendisi." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Hukuki" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/uk.coffee b/app/locale/uk.coffee index 13a2f129b..4844ec7ef 100644 --- a/app/locale/uk.coffee +++ b/app/locale/uk.coffee @@ -119,7 +119,7 @@ module.exports = nativeDescription: "українська мова", englishDesc boots: "Черевики" hue: "Відтінок" saturation: "Насиченість" - # lightness: "Яскравість" +# lightness: "Lightness" account_settings: title: "Налаштування акаунта" @@ -225,6 +225,20 @@ module.exports = nativeDescription: "українська мова", englishDesc # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "українська мова", englishDesc # av_other_debug_base_url: "Base (for debugging base.jade)" u_title: "Список користувачів" lg_title: "Останні ігри" +# clas: "CLAs" editor: main_title: "Редактори CodeCombat" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "українська мова", englishDesc # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "Юридичні нотатки" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "українська мова", englishDesc # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/ur.coffee b/app/locale/ur.coffee index 19c90913f..37a144ddc 100644 --- a/app/locale/ur.coffee +++ b/app/locale/ur.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." # level_difficulty: "Difficulty: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" # contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee index f9dc8839b..c953f3c8b 100644 --- a/app/locale/vi.coffee +++ b/app/locale/vi.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn 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." level_difficulty: "Khó: " -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -167,19 +167,19 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # gravatar_accounts: "As Seen On" # gravatar_profile_link: "Full Gravatar Profile" -# play_level: + play_level: # level_load_error: "Level could not be loaded: " - done: "Hoàn thành" + done: "Hoàn thành" # grid: "Grid" - customize_wizard: "Tùy chỉnh Wizard" + customize_wizard: "Tùy chỉnh Wizard" # home: "Home" - guide: "Hướng dẫn" - multiplayer: "Nhiều người chơi" - restart: "Khởi động lại" - goals: "Mục đích" + guide: "Hướng dẫn" + multiplayer: "Nhiều người chơi" + restart: "Khởi động lại" + goals: "Mục đích" # action_timeline: "Action Timeline" - click_to_select: "Kích vào đơn vị để chọn nó." - reload_title: "Tải lại tất cả mã?" + click_to_select: "Kích vào đơn vị để chọn nó." + reload_title: "Tải lại tất cả mã?" # reload_really: "Are you sure you want to reload this level back to the beginning?" # reload_confirm: "Reload All" # victory_title_prefix: "" @@ -225,6 +225,20 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -398,7 +413,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # 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: + contribute: # page_title: "Contributing" # character_classes_title: "Character Classes" # introduction_desc_intro: "We have high hopes for CodeCombat." @@ -481,8 +496,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." # counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." # counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." - counselor_attribute_2: "Rảnh rỗi một chút!" - counselor_join_desc: "Nói cho chúng tôi điều gì đó về bạn, bạn đã làm cái gì và bạn hứng thú về cái gì. Chúng tôi sẽ đưa bạn vào danh sách liên lạc và chúng tôi sẽ liên hệ khi chúng tôi có thể(không thường xuyên)." + counselor_attribute_2: "Rảnh rỗi một chút!" + counselor_join_desc: "Nói cho chúng tôi điều gì đó về bạn, bạn đã làm cái gì và bạn hứng thú về cái gì. Chúng tôi sẽ đưa bạn vào danh sách liên lạc và chúng tôi sẽ liên hệ khi chúng tôi có thể(không thường xuyên)." # more_about_counselor: "Learn More About Becoming a Counselor" # changes_auto_save: "Changes are saved automatically when you toggle checkboxes." # diligent_scribes: "Our Diligent Scribes:" @@ -492,7 +507,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # translating_diplomats: "Our Translating Diplomats:" # helpful_ambassadors: "Our Helpful Ambassadors:" -# classes: + classes: # archmage_title: "Archmage" # archmage_title_description: "(Coder)" # artisan_title: "Artisan" @@ -502,11 +517,11 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # scribe_title: "Scribe" # scribe_title_description: "(Article Editor)" # diplomat_title: "Diplomat" - diplomat_title_description: "(Người phiên dịch)" + diplomat_title_description: "(Người phiên dịch)" # ambassador_title: "Ambassador" - ambassador_title_description: "(Hỗ trợ)" - counselor_title: "Người tư vấn" - counselor_title_description: "(Chuyên gia/ Giáo viên)" + ambassador_title_description: "(Hỗ trợ)" + counselor_title: "Người tư vấn" + counselor_title_description: "(Chuyên gia/ Giáo viên)" # ladder: # please_login: "Please log in first before playing a ladder game." @@ -515,6 +530,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee index cdbe10a04..b29de278d 100644 --- a/app/locale/zh-HANS.coffee +++ b/app/locale/zh-HANS.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese campaign_player_created: "创建玩家" campaign_player_created_description: "……在这里你可以与你的小伙伴的创造力战斗 技术指导." level_difficulty: "难度:" -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " admin: av_title: "管理员视图" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese av_other_debug_base_url: "Base(用于调试 base.jade)" u_title: "用户列表" lg_title: "最新的游戏" +# clas: "CLAs" editor: main_title: "CodeCombat 编辑器" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" legal: page_title: "法律" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index e9c619244..9e1476995 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -87,7 +87,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese campaign_player_created: "玩家建立的關卡" campaign_player_created_description: "...挑戰同伴的創意 技術指導." level_difficulty: "難度" -# play_as: "Play As " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/app/locale/zh.coffee b/app/locale/zh.coffee index 97df3ea31..e4f9aa3a1 100644 --- a/app/locale/zh.coffee +++ b/app/locale/zh.coffee @@ -47,7 +47,7 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra log_out: "登出" recover: "找回账户" -# recover: + recover: recover_account_title: "帐户恢复" send_password: "发送恢复密码" @@ -87,7 +87,7 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # 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 " +# play_as: "Play As" # spectate: "Spectate" contact: @@ -225,6 +225,20 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # 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." +# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# 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, " # admin: # av_title: "Admin Views" @@ -235,6 +249,7 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # av_other_debug_base_url: "Base (for debugging base.jade)" # u_title: "User List" # lg_title: "Latest Games" +# clas: "CLAs" # editor: # main_title: "CodeCombat Editors" @@ -335,7 +350,7 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # 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." -# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that mather. The word impossible can't be found in his dictionary. Learning new skills is his joy!" +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" # legal: # page_title: "Legal" @@ -515,6 +530,8 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # 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:" # leaderboard: "Leaderboard" # battle_as: "Battle as " # summary_your: "Your " diff --git a/scripts/copy-i18n-tags.coffee b/scripts/copy-i18n-tags.coffee index 381aee5d8..9e125ace0 100644 --- a/scripts/copy-i18n-tags.coffee +++ b/scripts/copy-i18n-tags.coffee @@ -1,8 +1,8 @@ fs = require 'fs' -en = require('app/locale/en').translation +en = require('../app/locale/en').translation dir = fs.readdirSync 'app/locale' for file in dir when not (file in ['locale.coffee', 'en.coffee']) - contents = require('app/locale/' + file) + contents = require('../app/locale/' + file) categories = contents.translation lines = ["module.exports = nativeDescription: \"#{contents.nativeDescription}\", englishDescription: \"#{contents.englishDescription}\", translation:"] first = true From 36cfdfda46c9c5dcfc19fbd70f218bef3e4c15fc Mon Sep 17 00:00:00 2001 From: Mikhail Koltsov Date: Sat, 22 Mar 2014 23:17:15 +0400 Subject: [PATCH 16/30] Added labels above selected thangs in level-editor (issue #174) --- app/views/editor/level/thangs_tab_view.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/views/editor/level/thangs_tab_view.coffee b/app/views/editor/level/thangs_tab_view.coffee index cd4614f3b..7c8617a03 100644 --- a/app/views/editor/level/thangs_tab_view.coffee +++ b/app/views/editor/level/thangs_tab_view.coffee @@ -8,6 +8,7 @@ CocoCollection = require 'models/CocoCollection' Surface = require 'lib/surface/Surface' Thang = require 'lib/world/thang' LevelThangEditView = require './thang/edit' +Label = require "lib/surface/Label" ComponentsCollection = require 'collections/ComponentsCollection' # Moving the screen while dragging thangs constants @@ -217,6 +218,7 @@ module.exports = class ThangsTabView extends View # TODO: figure out a good way to have all Surface clicks and Treema clicks just proxy in one direction, so we can maintain only one way of handling selection and deletion onExtantThangSelected: (e) -> + @selectedExtantSprite?.setNameLabel null unless @selectedExtantSprite is e.sprite @selectedExtantThang = e.thang @selectedExtantSprite = e.sprite if e.thang and (key.alt or key.meta) @@ -228,6 +230,9 @@ module.exports = class ThangsTabView extends View @selectedExtantThangClickTime = new Date() treemaThang = _.find @thangsTreema.childrenTreemas, (treema) => treema.data.id is @selectedExtantThang.id if treemaThang + # Show the label above selected thang, notice that we may get here from thang-edit-view, so it will be selected but no label + # also covers selecting from Treema + @selectedExtantSprite.setNameLabel @selectedExtantSprite.thangType.get('name') + ': ' + @selectedExtantThang.id if not treemaThang.isSelected() treemaThang.select() @thangsTreema.$el.scrollTop(@thangsTreema.$el.find('.treema-children .treema-selected')[0].offsetTop) From 2316773cb1d1657125952c9c2eca495e72154524 Mon Sep 17 00:00:00 2001 From: Mikhail Koltsov Date: Sat, 22 Mar 2014 23:25:18 +0400 Subject: [PATCH 17/30] removed Label requierment --- app/views/editor/level/thangs_tab_view.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/editor/level/thangs_tab_view.coffee b/app/views/editor/level/thangs_tab_view.coffee index 7c8617a03..cb4728871 100644 --- a/app/views/editor/level/thangs_tab_view.coffee +++ b/app/views/editor/level/thangs_tab_view.coffee @@ -8,7 +8,6 @@ CocoCollection = require 'models/CocoCollection' Surface = require 'lib/surface/Surface' Thang = require 'lib/world/thang' LevelThangEditView = require './thang/edit' -Label = require "lib/surface/Label" ComponentsCollection = require 'collections/ComponentsCollection' # Moving the screen while dragging thangs constants From eec46dcb48b9c0a71e6e1ce73e9a68fd28697b26 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sat, 22 Mar 2014 14:28:18 -0700 Subject: [PATCH 18/30] Don't try to draw a grid if it's not going to work (no lands). --- app/lib/surface/Surface.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee index 901a5e414..675e57b0f 100644 --- a/app/lib/surface/Surface.coffee +++ b/app/lib/surface/Surface.coffee @@ -418,6 +418,8 @@ module.exports = Surface = class Surface extends CocoClass @gridShape.alpha = 0.125 @gridShape.graphics.beginStroke "blue" gridSize = Math.round(@world.size()[0] / 20) + unless gridSize > 0.1 + return console.error "Grid size is", gridSize, "so we can't draw a grid." wopStart = x: 0, y: 0 wopEnd = x: @world.size()[0], y: @world.size()[1] supStart = @camera.worldToSurface wopStart From 5ef6f6974fc1f1e9ec9ee5b75b2d367c92ea02a7 Mon Sep 17 00:00:00 2001 From: 3rr3s3v3n Date: Sun, 23 Mar 2014 11:39:35 +0100 Subject: [PATCH 19/30] Translation actived! I removed the # mark from the lines I've translated yesterday. --- app/locale/it.coffee | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/locale/it.coffee b/app/locale/it.coffee index b639bf160..516e56204 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -523,19 +523,19 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # summary_losses: " Losses" # rank_no_code: "No New Code to Rank" # rank_my_game: "Rank My Game!" -# rank_submitting: "Inviando..." -# rank_submitted: "Inviato per essere Valutato" -# rank_failed: "Impossibile Valutare" -# rank_being_ranked: "Il Gioco è stato Valutato" -# code_being_simulated: "Il tuo nuovo codice sarà simulato da altri giocatori per essere valutato. Sarà aggiornato ad ogni nuova partita." -# no_ranked_matches_pre: "Nessuna partita valutata per " -# no_ranked_matches_post: " squadra! Gioca contro altri avversari e poi torna qui affinchè la tua partita venga valutata." -# choose_opponent: "Scegli un avversario" -# tutorial_play: "Gioca il Tutorial" -# tutorial_recommended: "Consigliato se questa è la tua primissima partita" -# tutorial_skip: "Salta il Tutorial" -# tutorial_not_sure: "Non sei sicuro di quello che sta accadendo?" -# tutorial_play_first: "Prima di tutto gioca al Tutorial." + rank_submitting: "Inviando..." + rank_submitted: "Inviato per essere Valutato" + rank_failed: "Impossibile Valutare" + rank_being_ranked: "Il Gioco è stato Valutato" + code_being_simulated: "Il tuo nuovo codice sarà simulato da altri giocatori per essere valutato. Sarà aggiornato ad ogni nuova partita." + no_ranked_matches_pre: "Nessuna partita valutata per " + no_ranked_matches_post: " squadra! Gioca contro altri avversari e poi torna qui affinchè la tua partita venga valutata." + choose_opponent: "Scegli un avversario" + tutorial_play: "Gioca il Tutorial" + tutorial_recommended: "Consigliato se questa è la tua primissima partita" + tutorial_skip: "Salta il Tutorial" + tutorial_not_sure: "Non sei sicuro di quello che sta accadendo?" + tutorial_play_first: "Prima di tutto gioca al Tutorial." # simple_ai: "Simple AI" # warmup: "Warmup" # vs: "VS" From f4de280cee8fdb57f833d751f72f08b0e0325551 Mon Sep 17 00:00:00 2001 From: 3rr3s3v3n Date: Sun, 23 Mar 2014 11:53:39 +0100 Subject: [PATCH 20/30] Translating more Lines. Password remains password in Italian, such as VS. --- app/locale/it.coffee | 46 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/locale/it.coffee b/app/locale/it.coffee index 516e56204..d226482d6 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -66,12 +66,12 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t no_ie: "CodeCombat non supporta Internet Explorer 9 o browser precedenti. Ci dispiace!" no_mobile: "CodeCombat non è stato progettato per dispositivi mobile e potrebbe non funzionare!" play: "Gioca" -# 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" + old_browser: "Accidenti, il tuo browser è troppo vecchio per giocare a CodeCombat. Mi spiace!" + old_browser_suffix: "Puoi provare lo stesso, ma probabilmente non funzionerà." + campaign: "Campagna" + for_beginners: "Per Principianti" # multiplayer: "Multiplayer" -# for_developers: "For Developers" + for_developers: "Per Sviluppatori" play: choose_your_level: "Scegli il tuo livello" @@ -88,7 +88,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t campaign_player_created_description: "... nei quali affronterai la creatività dei tuoi compagni Stregoni Artigiani." level_difficulty: "Difficoltà: " play_as: "Gioca come " -# spectate: "Spectate" + spectate: "Spettatore" contact: contact_us: "Contatta CodeCombat" @@ -187,8 +187,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t victory_sign_up: "Registrati per gli aggiornamenti" victory_sign_up_poke: "Vuoi ricevere le ultime novità per email? Crea un account gratuito e ti terremo aggiornato!" victory_rate_the_level: "Vota il livello: " -# victory_rank_my_game: "Rank My Game" -# victory_ranking_game: "Submitting..." + victory_rank_my_game: "Valuta la mia partita" + victory_ranking_game: "Inviando..." # victory_return_to_ladder: "Return to Ladder" victory_play_next_level: "Gioca il prossimo livello" victory_go_home: "Torna alla pagina iniziale" @@ -212,8 +212,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t tome_select_a_thang: "Seleziona qualcuno per " tome_available_spells: "Incantesimi disponibili" hud_continue: "Continua (premi Maiusc-Spazio)" -# spell_saved: "Spell Saved" -# skip_tutorial: "Skip (esc)" + spell_saved: "Magia Salvata" + skip_tutorial: "Salta (esc)" # editor_config: "Editor Config" # editor_config_title: "Editor Configuration" # editor_config_keybindings_label: "Key Bindings" @@ -299,23 +299,23 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t description: "Descrizione" or: "o" email: "Email" -# password: "Password" + password: "Password" message: "Messaggio" -# code: "Code" + code: "Codice" # ladder: "Ladder" -# when: "When" -# opponent: "Opponent" + when: "Quando" + opponent: "Avversario" # rank: "Rank" -# score: "Score" -# win: "Win" -# loss: "Loss" + score: "Punteggio" + win: "Vittoria" + loss: "Sconfitta" # tie: "Tie" -# easy: "Easy" -# medium: "Medium" -# hard: "Hard" + easy: "Facile" + medium: "Medio" + hard: "Difficile" about: - who_is_codecombat: "Chi c'è inCodeCombat?" + who_is_codecombat: "Chi c'è in CodeCombat?" why_codecombat: "Perché CodeCombat?" who_description_prefix: "insieme hanno iniziato CodeCombat nel 2013. Abbiamo anche creato " who_description_suffix: "nel 2008, portandola al primo posto nelle applicazioni web e iOS per imparare a scrivere i caratteri cinesi e giapponesi." @@ -511,7 +511,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # ladder: # please_login: "Please log in first before playing a ladder game." # my_matches: "My Matches" -# simulate: "Simulate" + simulate: "Simula" # simulation_explanation: "By simulating games you can get your game ranked faster!" # simulate_games: "Simulate Games!" # simulate_all: "RESET AND SIMULATE GAMES" @@ -538,7 +538,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t tutorial_play_first: "Prima di tutto gioca al Tutorial." # simple_ai: "Simple AI" # warmup: "Warmup" -# vs: "VS" + vs: "VS" # multiplayer_launch: # introducing_dungeon_arena: "Introducing Dungeon Arena" From 970552a6d6df5ebfa8fae27c468c695fc3bd3003 Mon Sep 17 00:00:00 2001 From: dpen2000 Date: Sun, 23 Mar 2014 13:34:11 +0000 Subject: [PATCH 21/30] Fix "Simulating game between" line to only have one "and" --- app/views/play/ladder_view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/play/ladder_view.coffee b/app/views/play/ladder_view.coffee index 9341f97f7..fc05cb0c2 100644 --- a/app/views/play/ladder_view.coffee +++ b/app/views/play/ladder_view.coffee @@ -114,7 +114,7 @@ module.exports = class LadderView extends RootView for index in [0...creatorNames.length] unless creatorNames[index] creatorNames[index] = "Anonymous" - @simulationStatus += " and " + creatorNames[index] + @simulationStatus += (if index != 0 then " and " else "") + creatorNames[index] @simulationStatus += "..." catch e console.log "There was a problem with the named simulation status: #{e}" From 20e111d307ed8bf01cab7aec942b3e512c5413ce Mon Sep 17 00:00:00 2001 From: Alexei Nikitin Date: Sun, 23 Mar 2014 07:30:14 -0700 Subject: [PATCH 22/30] Update ru.coffee --- app/locale/ru.coffee | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee index 3b5dc211c..e9876b20d 100644 --- a/app/locale/ru.coffee +++ b/app/locale/ru.coffee @@ -225,20 +225,20 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi editor_config_indentguides_description: "Отображение вертикальных линий для лучшего обзора отступов." editor_config_behaviors_label: "Умное поведение" editor_config_behaviors_description: "Автозавершать квадратные, фигурные скобки и кавычки." -# 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_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." -# 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, " + loading_ready: "Готово!" + tip_insert_positions: "Shift+Клик по карте вставит координаты в редактор заклинаний." + tip_toggle_play: "Переключайте воспроизведение/паузу комбинацией Ctrl+P." + tip_scrub_shortcut: "Ctrl+[ и Ctrl+] - перемотка назад и вперёд." + tip_guide_exists: "Щёлкните \"руководство\" наверху страницы для получения полезной информации." + tip_open_source: "Исходный код CodeCombat открыт на 100%!" + tip_beta_launch: "CodeCombat запустил бета-тестирование в октябре 2013." + tip_js_beginning: "JavaScript это только начало." + tip_autocast_setting: "Изменяйте настройки авточтения заклинания, щёлкнув по шестерёнке на кнопке прочтения." + tip_baby_coders: "В будущем, даже младенцы будут Архимагами." + tip_morale_improves: "Загрузка будет продолжаться, пока боевой дух не улучшится." + tip_all_species: "Мы верим в равные возможности для обучения программированию для всех видов." + tip_reticulating: "Ретикуляция сплайнов." + tip_harry: "Ты волшебник, " admin: av_title: "Админ панель" @@ -249,7 +249,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi av_other_debug_base_url: "База (для отладки base.jade)" u_title: "Список пользователей" lg_title: "Последние игры" -# clas: "CLAs" + clas: "ЛСС" editor: main_title: "Редакторы CodeCombat" @@ -530,8 +530,8 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi simulation_explanation: "Симулированием игр вы сможете быстрее получить оценку игры!" simulate_games: "Симулировать игры!" simulate_all: "СБРОСИТЬ И СИМУЛИРОВАТЬ ИГРЫ" -# games_simulated_by: "Games simulated by you:" -# games_simulated_for: "Games simulated for you:" + games_simulated_by: "Игры, симулированные вами:" + games_simulated_for: "Игры, симулированные за вас:" leaderboard: "Таблица лидеров" battle_as: "Сразиться за " summary_your: "Ваши " From edeeb3c3eb73e68d9c4bfde757f53f46b9fdb7a9 Mon Sep 17 00:00:00 2001 From: Mikhail Koltsov Date: Sun, 23 Mar 2014 20:21:11 +0400 Subject: [PATCH 23/30] some work on arrows --- app/lib/surface/CocoSprite.coffee | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index d223ac571..d84dcc2f0 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -255,9 +255,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass if @thangType.get('name') is 'Arrow' # scale the arrow so it appears longer when flying parallel to horizon angle = @getRotation() - angle = -angle if angle < 0 - angle = 180 - angle if angle > 90 - scaleX = 0.5 + 0.5 * (90 - angle) / 90 + scaleX = 0.5 + 0.5 * angleDiffFactorFrom90(angle) scaleFactorX = @thang.scaleFactorX ? @scaleFactor scaleFactorY = @thang.scaleFactorY ? @scaleFactor @imageObject.scaleX = @originalScaleX * scaleX * scaleFactorX @@ -275,10 +273,29 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass if @options.showInvisible @imageObject.alpha = Math.max 0.5, @imageObject.alpha + angleDiffFactorFrom90: (angle) -> + # how much horizontal is angle, which must be (-180, 180]. + # 1 for parallel to horizon, 0 for orthogonal, monotonuous in between + angle = -angle if angle < 0 + angle = 180 - angle if angle > 90 + return (90 - angle) / 90 + updateRotation: (imageObject) -> rotationType = @thangType.get('rotationType') return if rotationType is 'fixed' rotation = @getRotation() + if False and @thangType.get('name') is 'Arrow' + # Makes arrow rotate properly when travelling upwards or downwards with z-coordinate. + # If it's travelling parallel to horizon, then the arc must be more visible. + # But when it's perpendicular, the arrow must be scaled, not rotated, to pretend + # it is getting closer to the camera. + velocity = @thang.velocity.z + originallyHeaded = 360 - @thang.initialRotation / Math.PI * 180 + originallyHeaded -= 360 if originallyHeaded > 180 + angleFactor = angleDiffFactorFrom90(originallyHeaded) # the more it is, the more deviation from original direction + speedLimit = 7 # for normalization purposes + velocityFactor = velocity / speedLimit # same as angleFactor + rotation = originallyHeaded + velocityFactor * angleFactor * 45 imageObject ?= @imageObject return imageObject.rotation = rotation if not rotationType @updateIsometricRotation(rotation, imageObject) From 72b88a3ee90eb1649a3fa3e20843fed86ed33268 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sun, 23 Mar 2014 09:30:01 -0700 Subject: [PATCH 24/30] First pass on setting up gplus friends on the ladder page. --- app/application.coffee | 4 +- app/lib/GPlusHandler.coffee | 51 +++++++++++++-- app/views/play/ladder/ladder_tab.coffee | 84 +++++++++++++++++-------- server/levels/level_handler.coffee | 23 ++++--- server/users/user_handler.coffee | 7 ++- 5 files changed, 123 insertions(+), 46 deletions(-) diff --git a/app/application.coffee b/app/application.coffee index caf648679..cc6acd63b 100644 --- a/app/application.coffee +++ b/app/application.coffee @@ -28,8 +28,8 @@ preload = (arrayOfImages) -> Application = initialize: -> Router = require('lib/Router') @tracker = new Tracker() - new FacebookHandler() - new GPlusHandler() + @facebookHandler = new FacebookHandler() + @gplusHandler = new GPlusHandler() $(document).bind 'keydown', preventBackspace preload(COMMON_FILES) diff --git a/app/lib/GPlusHandler.coffee b/app/lib/GPlusHandler.coffee index 4b3df9e5b..2ffd27805 100644 --- a/app/lib/GPlusHandler.coffee +++ b/app/lib/GPlusHandler.coffee @@ -2,6 +2,7 @@ CocoClass = require 'lib/CocoClass' {me, CURRENT_USER_KEY} = require 'lib/auth' {backboneFailure} = require 'lib/errors' storage = require 'lib/storage' +GPLUS_TOKEN_KEY = 'gplusToken' # gplus user object props to userPropsToSave = @@ -14,19 +15,46 @@ fieldsToFetch = 'displayName,gender,image,name(familyName,givenName),id' plusURL = '/plus/v1/people/me?fields='+fieldsToFetch revokeUrl = 'https://accounts.google.com/o/oauth2/revoke?token=' clientID = "800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com" +scope = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email" module.exports = GPlusHandler = class GPlusHandler extends CocoClass constructor: -> + @accessToken = storage.load GPLUS_TOKEN_KEY super() subscriptions: 'gplus-logged-in':'onGPlusLogin' + 'gapi-loaded':'onGPlusLoaded' + onGPlusLoaded: -> + session_state = null + if @accessToken + # We need to check the current state, given our access token + gapi.auth.setToken 'token', @accessToken + session_state = @accessToken.session_state + gapi.auth.checkSessionState({client_id:clientID, session_state:session_state}, @onCheckedSessionState) + else + # If we ran checkSessionState, it might return true, that the user is logged into Google, but has not authorized us + @loggedIn = false + func = => @trigger 'checked-state' + setTimeout func, 1 + + onCheckedSessionState: (@loggedIn) => + @trigger 'checked-state' + + reauthorize: -> + params = + 'client_id' : clientID + 'scope' : scope + gapi.auth.authorize params, @onGPlusLogin + onGPlusLogin: (e) => - return if e._aa # this seems to show that it was auto generated on page load - return if not me - @accessToken = e.access_token - + @loggedIn = true + storage.save(GPLUS_TOKEN_KEY, e) + @accessToken = e + @trigger 'logged-in' + return if (not me) or me.get 'gplusID' # so only get more data + # email and profile data loaded separately @responsesComplete = 0 gapi.client.request(path:plusURL, callback:@onPersonEntityReceived) @@ -68,11 +96,22 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass patch[key] = me.get(key) for gplusKey, key of userPropsToSave patch._id = me.id patch.email = me.get('email') + wasAnonymous = me.get('anonymous') me.save(patch, { patch: true error: backboneFailure, - url: "/db/user?gplusID=#{gplusID}&gplusAccessToken=#{@accessToken}" + url: "/db/user?gplusID=#{gplusID}&gplusAccessToken=#{@accessToken.access_token}" success: (model) -> storage.save(CURRENT_USER_KEY, model.attributes) - window.location.reload() + window.location.reload() if wasAnonymous and not model.get('anonymous') }) + + loadFriends: (friendsCallback) -> + return friendsCallback() unless @loggedIn + expires_in = if @accessToken then parseInt(@accessToken.expires_at) - new Date().getTime()/1000 else -1 + onReauthorized = => gapi.client.request({path:'/plus/v1/people/me/people/visible', callback: friendsCallback}) + if expires_in < 0 + @reauthorize() + @listenToOnce(@, 'logged-in', onReauthorized) + else + onReauthorized() diff --git a/app/views/play/ladder/ladder_tab.coffee b/app/views/play/ladder/ladder_tab.coffee index 81450f723..d629c7d94 100644 --- a/app/views/play/ladder/ladder_tab.coffee +++ b/app/views/play/ladder/ladder_tab.coffee @@ -19,10 +19,10 @@ module.exports = class LadderTabView extends CocoView id: 'ladder-tab-view' template: require 'templates/play/ladder/ladder_tab' startsLoading: true - + events: 'click .connect-facebook': 'onConnectFacebook' - + subscriptions: 'facebook-logged-in': 'onConnectedWithFacebook' @@ -33,45 +33,77 @@ module.exports = class LadderTabView extends CocoView @refreshLadder() @checkFriends() + checkFriends: -> + @loadingFacebookFriends = true + FB.getLoginStatus (response) => + @facebookStatus = response.status + if @facebookStatus is 'connected' then @loadFacebookFriendSessions() else @loadingFacebookFriends = false + + if application.gplusHandler.loggedIn is undefined + @loadingGPlusFriends = true + @listenToOnce(application.gplusHandler, 'checked-state', @gplusSessionStateLoaded) + else + @gplusSessionStateLoaded() + + # FACEBOOK + + # Connect button pressed + onConnectFacebook: -> @connecting = true FB.login() + + onConnectedWithFacebook: -> location.reload() if @connecting + + # Load friends - onConnectedWithFacebook: -> - location.reload() if @connecting - - checkFriends: -> - @loadingFriends = true - FB.getLoginStatus (response) => - @facebookStatus = response.status - if @facebookStatus is 'connected' - @loadFriendSessions() - else - @loadingFriends = false - @renderMaybe() - - loadFriendSessions: -> + loadFacebookFriendSessions: -> FB.api '/me/friends', (response) => @facebookData = response.data - console.log 'got facebookData', @facebookData levelFrag = "#{@level.get('original')}.#{@level.get('version').major}" - url = "/db/level/#{levelFrag}/leaderboard_friends" + url = "/db/level/#{levelFrag}/leaderboard_facebook_friends" $.ajax url, { data: { friendIDs: (f.id for f in @facebookData) } method: 'POST' - success: @facebookFriendsLoaded + success: @onFacebookFriendSessionsLoaded } - facebookFriendsLoaded: (result) => + onFacebookFriendSessionsLoaded: (result) => friendsMap = {} friendsMap[friend.id] = friend.name for friend in @facebookData for friend in result friend.facebookName = friendsMap[friend.facebookID] friend.otherTeam = if friend.team is 'humans' then 'ogres' else 'humans' - @friends = result - @loadingFriends = false + @facebookFriends = result + @loadingFacebookFriends = false @renderMaybe() + # GOOGLE PLUS + + gplusSessionStateLoaded: -> + if application.gplusHandler.loggedIn + @loadingGPlusFriends = true + application.gplusHandler.loadFriends @gplusFriendsLoaded + else + @loadingGPlusFriends = false + @renderMaybe() + + gplusFriendsLoaded: (friends) => + @gplusData = friends.items + levelFrag = "#{@level.get('original')}.#{@level.get('version').major}" + url = "/db/level/#{levelFrag}/leaderboard_gplus_friends" + $.ajax url, { + data: { friendIDs: (f.id for f in @gplusData) } + method: 'POST' + success: @onGPlusFriendSessionsLoaded + } + + onGPlusFriendSessionsLoaded: (result) => + @loadingGPlusFriends = false + @renderMaybe() + + # LADDER LOADING + refreshLadder: -> promises = [] for team in @teams @@ -83,12 +115,11 @@ module.exports = class LadderTabView extends CocoView $.when(promises...).then(@leaderboardsLoaded) leaderboardsLoaded: => - return if @destroyed @loadingLeaderboards = false @renderMaybe() - + renderMaybe: -> - return if @loadingFriends or @loadingLeaderboards + return if @loadingFacebookFriends or @loadingLeaderboards @startsLoading = false @render() @@ -99,8 +130,9 @@ module.exports = class LadderTabView extends CocoView ctx.teams = @teams team.leaderboard = @leaderboards[team.id] for team in @teams ctx.levelID = @levelID - ctx.friends = @friends + ctx.friends = @facebookFriends ctx.onFacebook = @facebookStatus is 'connected' + ctx.onGPlus = application.gplusHandler.loggedIn ctx class LeaderboardData diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 21a0bcc42..c58738d20 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -34,7 +34,8 @@ LevelHandler = class LevelHandler extends Handler return @getMySessions(req, res, args[0]) if args[1] is 'my_sessions' return @getFeedback(req, res, args[0]) if args[1] is 'feedback' return @getRandomSessionPair(req,res,args[0]) if args[1] is 'random_session_pair' - return @getLeaderboardFriends(req, res, args[0]) if args[1] is 'leaderboard_friends' + 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' return @sendNotFoundError(res) @@ -164,13 +165,15 @@ LevelHandler = class LevelHandler extends Handler req.query.team ?= 'humans' req.query.limit = parseInt(req.query.limit) ? 20 - getLeaderboardFriends: (req, res, id) -> + getLeaderboardFacebookFriends: (req, res, id) -> @getLeaderboardFriends(req, res, id, 'facebookID') + getLeaderboardGPlusFriends: (req, res, id) -> @getLeaderboardFriends(req, res, id, 'gplusID') + getLeaderboardFriends: (req, res, id, serviceProperty) -> friendIDs = req.body.friendIDs or [] return res.send([]) unless friendIDs.length - query = User.find({facebookID:{$in:friendIDs}}) - .select('facebookID name') - .lean() + q = {} + q[serviceProperty] = {$in:friendIDs} + query = User.find(q).select("#{serviceProperty} name").lean() query.exec (err, userResults) -> return res.send([]) unless userResults.length @@ -178,16 +181,16 @@ LevelHandler = class LevelHandler extends Handler userIDs = (r._id+'' for r in userResults) q = {'level.original':id, 'level.majorVersion': parseInt(version), creator: {$in:userIDs}, totalScore:{$exists:true}} query = Session.find(q) - .select('creator creatorName totalScore team') - .lean() + .select('creator creatorName totalScore team') + .lean() query.exec (err, sessionResults) -> return res.send([]) unless sessionResults.length userMap = {} - userMap[u._id] = u.facebookID for u in userResults - session.facebookID = userMap[session.creator] for session in sessionResults + userMap[u._id] = u[serviceProperty] for u in userResults + session[serviceProperty] = userMap[session.creator] for session in sessionResults res.send(sessionResults) - + getRandomSessionPair: (req, res, slugOrID) -> findParameters = {} if Handler.isID slugOrID diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index c822f9139..174445436 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -9,14 +9,17 @@ errors = require '../commons/errors' async = require 'async' serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset'] -privateProperties = ['permissions', 'email', 'firstName', 'lastName', 'gender', 'facebookID', 'music', 'volume', 'aceConfig'] +privateProperties = [ + 'permissions', 'email', 'firstName', 'lastName', 'gender', 'facebookID', + 'gplusID', 'music', 'volume', 'aceConfig' +] UserHandler = class UserHandler extends Handler modelClass: User editableProperties: [ 'name', 'photoURL', 'password', 'anonymous', 'wizardColor1', 'volume', - 'firstName', 'lastName', 'gender', 'facebookID', 'emailSubscriptions', + 'firstName', 'lastName', 'gender', 'facebookID', 'gplusID', 'emailSubscriptions', 'testGroupNumber', 'music', 'hourOfCode', 'hourOfCodeComplete', 'preferredLanguage', 'wizard', 'aceConfig', 'autocastDelay', 'lastLevel' ] From 7ba959045ab4ac368daf32806ba1617bc32661d1 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sun, 23 Mar 2014 10:00:16 -0700 Subject: [PATCH 25/30] A slight enhancement to #650, plus fixing CocoModels thinking they're modified when schema defaults have been added. --- app/models/CocoModel.coffee | 8 +++++++- app/views/editor/level/settings_tab_view.coffee | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index 59e9af816..6484c3ae6 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -86,7 +86,9 @@ class CocoModel extends Backbone.Model res markToRevert: -> - if @type() != 'ThangType' + if @type() is 'ThangType' + @_revertAttributes = _.clone @attributes # No deep clones for these! + else @_revertAttributes = $.extend(true, {}, @attributes) revert: -> @@ -120,14 +122,18 @@ class CocoModel extends Backbone.Model addSchemaDefaults: -> return if @addedSchemaDefaults or not @constructor.hasSchema() @addedSchemaDefaults = true + addedAnything = false for prop, defaultValue of @constructor.schema.attributes.default or {} continue if @get(prop)? #console.log "setting", prop, "to", defaultValue, "from attributes.default" @set prop, defaultValue + addedAnything = true for prop, sch of @constructor.schema.attributes.properties or {} continue if @get(prop)? #console.log "setting", prop, "to", sch.default, "from sch.default" if sch.default? @set prop, sch.default if sch.default? + addedAnything = true + @markToRevert() if addedAnything getReferencedModels: (data, schema, path='/', shouldLoadProjection=null) -> # returns unfetched model shells for every referenced doc in this model diff --git a/app/views/editor/level/settings_tab_view.coffee b/app/views/editor/level/settings_tab_view.coffee index 7a1290db1..7556c4a4f 100644 --- a/app/views/editor/level/settings_tab_view.coffee +++ b/app/views/editor/level/settings_tab_view.coffee @@ -8,7 +8,7 @@ module.exports = class SettingsTabView extends View id: 'editor-level-settings-tab-view' className: 'tab-pane' template: template - + # not thangs or scripts or the backend stuff editableSettings: [ 'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals', @@ -39,7 +39,7 @@ module.exports = class SettingsTabView extends View thangIDs: thangIDs nodeClasses: thang: nodes.ThangNode - + @settingsTreema = @$el.find('#settings-treema').treema treemaOptions @settingsTreema.build() @settingsTreema.open() From 111973e1c87bab626ac8be19cecc509ae7fc8ab2 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sun, 23 Mar 2014 10:29:08 -0700 Subject: [PATCH 26/30] Maybe this will be better - more on #650. --- app/models/CocoModel.coffee | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index 6484c3ae6..c0014deab 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -34,18 +34,22 @@ class CocoModel extends Backbone.Model onLoaded: -> @loaded = true @loading = false - @markToRevert() - if @saveBackups - existing = storage.load @id - if existing - @set(existing, {silent:true}) - CocoModel.backedUp[@id] = @ + if @constructor.schema?.loaded + @markToRevert() + @loadFromBackup() set: -> res = super(arguments...) @saveBackup() if @saveBackups and @loaded and @hasLocalChanges() res + loadFromBackup: -> + return unless @saveBackups + existing = storage.load @id + if existing + @set(existing, {silent:true}) + CocoModel.backedUp[@id] = @ + saveBackup: -> storage.save(@id, @attributes) CocoModel.backedUp[@id] = @ @@ -122,18 +126,17 @@ class CocoModel extends Backbone.Model addSchemaDefaults: -> return if @addedSchemaDefaults or not @constructor.hasSchema() @addedSchemaDefaults = true - addedAnything = false for prop, defaultValue of @constructor.schema.attributes.default or {} continue if @get(prop)? #console.log "setting", prop, "to", defaultValue, "from attributes.default" @set prop, defaultValue - addedAnything = true for prop, sch of @constructor.schema.attributes.properties or {} continue if @get(prop)? #console.log "setting", prop, "to", sch.default, "from sch.default" if sch.default? @set prop, sch.default if sch.default? - addedAnything = true - @markToRevert() if addedAnything + if @loaded + @markToRevert() + @loadFromBackup() getReferencedModels: (data, schema, path='/', shouldLoadProjection=null) -> # returns unfetched model shells for every referenced doc in this model From 446726acc95516149920783ddb674af5b757d731 Mon Sep 17 00:00:00 2001 From: Mikhail Koltsov Date: Sun, 23 Mar 2014 22:13:07 +0400 Subject: [PATCH 27/30] done rotating, looks good in Zone of Danger (#46) --- app/lib/surface/CocoSprite.coffee | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index d84dcc2f0..8b19b7ca7 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -255,7 +255,9 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass if @thangType.get('name') is 'Arrow' # scale the arrow so it appears longer when flying parallel to horizon angle = @getRotation() - scaleX = 0.5 + 0.5 * angleDiffFactorFrom90(angle) + angle = -angle if angle < 0 + angle = 180 - angle if angle > 90 + scaleX = 0.5 + 0.5 * (90 - angle) / 90 scaleFactorX = @thang.scaleFactorX ? @scaleFactor scaleFactorY = @thang.scaleFactorY ? @scaleFactor @imageObject.scaleX = @originalScaleX * scaleX * scaleFactorX @@ -273,29 +275,20 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass if @options.showInvisible @imageObject.alpha = Math.max 0.5, @imageObject.alpha - angleDiffFactorFrom90: (angle) -> - # how much horizontal is angle, which must be (-180, 180]. - # 1 for parallel to horizon, 0 for orthogonal, monotonuous in between - angle = -angle if angle < 0 - angle = 180 - angle if angle > 90 - return (90 - angle) / 90 - updateRotation: (imageObject) -> rotationType = @thangType.get('rotationType') return if rotationType is 'fixed' rotation = @getRotation() - if False and @thangType.get('name') is 'Arrow' - # Makes arrow rotate properly when travelling upwards or downwards with z-coordinate. - # If it's travelling parallel to horizon, then the arc must be more visible. - # But when it's perpendicular, the arrow must be scaled, not rotated, to pretend - # it is getting closer to the camera. + if @thangType.get('name') is 'Arrow' velocity = @thang.velocity.z - originallyHeaded = 360 - @thang.initialRotation / Math.PI * 180 - originallyHeaded -= 360 if originallyHeaded > 180 - angleFactor = angleDiffFactorFrom90(originallyHeaded) # the more it is, the more deviation from original direction - speedLimit = 7 # for normalization purposes - velocityFactor = velocity / speedLimit # same as angleFactor - rotation = originallyHeaded + velocityFactor * angleFactor * 45 + factor = rotation + factor = -factor if factor < 0 + flip = 1 + if factor > 90 + factor = 180 - factor + flip = -1 + factor = (90 - factor) / 90 + rotation += flip * (velocity / 12) * factor * 45 imageObject ?= @imageObject return imageObject.rotation = rotation if not rotationType @updateIsometricRotation(rotation, imageObject) From 13338afe3d3c593b20919cefd8f4462ecb0a55e6 Mon Sep 17 00:00:00 2001 From: Mikhail Koltsov Date: Sun, 23 Mar 2014 23:51:46 +0400 Subject: [PATCH 28/30] Now absolutely done scaling (#46) also commented math's out. --- app/lib/surface/CocoSprite.coffee | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index 8b19b7ca7..914c65c13 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -253,7 +253,14 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass scaleX = if @getActionProp 'flipX' then -1 else 1 scaleY = if @getActionProp 'flipY' then -1 else 1 if @thangType.get('name') is 'Arrow' - # scale the arrow so it appears longer when flying parallel to horizon + # Scales the arrow so it appears longer when flying parallel to horizon. + # To do that, we convert angle to [0, 90] (mirroring half-planes twice), then make linear function out of it: + # (a - x) / a: equals 1 when x = 0, equals 0 when x = a, monotonous in between. That gives us some sort of + # degenerative multiplier. + # For our puproses, a = 90 - the direction straight upwards. + # Then we use r + (1 - r) * x function with r = 0.5, so that + # maximal scale equals 1 (when x is at it's maximum) and minimal scale is 0.5. + # Notice that the value of r is empirical. angle = @getRotation() angle = -angle if angle < 0 angle = 180 - angle if angle > 90 @@ -280,15 +287,23 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass return if rotationType is 'fixed' rotation = @getRotation() if @thangType.get('name') is 'Arrow' + # Rotates the arrow to see it arc based on velocity.z. + # At midair we must see the original angle (delta = 0), but at launch time + # and arrow must point upwards/downwards respectively. + # The curve must consider two variables: speed and angle to camera: + # higher angle -> higher steep + # higher speed -> higher steep (0 at midpoint). + # All constants are empirical. Notice that rotation here does not affect thang's state - it is just the effect. + # Thang's rotation is always pointing where it is heading. velocity = @thang.velocity.z factor = rotation factor = -factor if factor < 0 flip = 1 if factor > 90 factor = 180 - factor - flip = -1 - factor = (90 - factor) / 90 - rotation += flip * (velocity / 12) * factor * 45 + flip = -1 # when the arrow is on the left, 'up' means subtracting + factor = Math.max(factor / 90, 0.4) # between 0.4 and 1.0 + rotation += flip * (velocity / 12) * factor * 45 # theoretically, 45 is the maximal delta we can make here imageObject ?= @imageObject return imageObject.rotation = rotation if not rotationType @updateIsometricRotation(rotation, imageObject) From d85dd9f62c06917e5b1f8ea210bdd3399d8ce03f Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sun, 23 Mar 2014 14:15:06 -0700 Subject: [PATCH 29/30] Bringing in #664, but only when maximizesArc is on. --- app/lib/surface/CocoSprite.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index 914c65c13..0b6e450e2 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -252,10 +252,10 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass return scaleX = if @getActionProp 'flipX' then -1 else 1 scaleY = if @getActionProp 'flipY' then -1 else 1 - if @thangType.get('name') is 'Arrow' + if @thang.maximizesArc and @thangType.get('name') in ['Arrow', 'Spear'] # Scales the arrow so it appears longer when flying parallel to horizon. # To do that, we convert angle to [0, 90] (mirroring half-planes twice), then make linear function out of it: - # (a - x) / a: equals 1 when x = 0, equals 0 when x = a, monotonous in between. That gives us some sort of + # (a - x) / a: equals 1 when x = 0, equals 0 when x = a, monotonous in between. That gives us some sort of # degenerative multiplier. # For our puproses, a = 90 - the direction straight upwards. # Then we use r + (1 - r) * x function with r = 0.5, so that @@ -286,12 +286,12 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass rotationType = @thangType.get('rotationType') return if rotationType is 'fixed' rotation = @getRotation() - if @thangType.get('name') is 'Arrow' + if @thang.maximizesArc and @thangType.get('name') in ['Arrow', 'Spear'] # Rotates the arrow to see it arc based on velocity.z. # At midair we must see the original angle (delta = 0), but at launch time # and arrow must point upwards/downwards respectively. - # The curve must consider two variables: speed and angle to camera: - # higher angle -> higher steep + # The curve must consider two variables: speed and angle to camera: + # higher angle -> higher steep # higher speed -> higher steep (0 at midpoint). # All constants are empirical. Notice that rotation here does not affect thang's state - it is just the effect. # Thang's rotation is always pointing where it is heading. From b922b9dd202d7d0fe100851b17ece8c825cd21e4 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sun, 23 Mar 2014 15:34:38 -0700 Subject: [PATCH 30/30] Increased number of matches played. --- server/queues/scoring.coffee | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index fac34b59f..a48c4d0eb 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -54,30 +54,30 @@ addPairwiseTaskToQueue = (taskPair, cb) -> sendEachTaskPairToTheQueue taskPairs, (taskPairError) -> if taskPairError? then return cb taskPairError,false cb null, true - + module.exports.resimulateAllSessions = (req, res) -> unless isUserAdmin req then return errors.unauthorized res, "Unauthorized. Even if you are authorized, you shouldn't do this" - + originalLevelID = req.body.originalLevelID levelMajorVersion = parseInt(req.body.levelMajorVersion) - + findParameters = submitted: true - level: + level: original: originalLevelID - majorVersion: levelMajorVersion + majorVersion: levelMajorVersion query = LevelSession .find(findParameters) .lean() - + query.exec (err, result) -> if err? then return errors.serverError res, err result = _.sample result, 10 async.each result, resimulateSession.bind(@,originalLevelID,levelMajorVersion), (err) -> if err? then return errors.serverError res, err sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"} - + resimulateSession = (originalLevelID, levelMajorVersion, session, cb) => sessionUpdateObject = submitted: true @@ -250,7 +250,7 @@ determineIfSessionShouldContinueAndUpdateLog = (sessionID, sessionRank, cb) -> cb null, true else ratio = (updatedSession.numberOfLosses) / (totalNumberOfGamesPlayed) - if ratio > 0.2 + if ratio > 0.33 cb null, false console.log "Ratio(#{ratio}) is bad, ending simulation" else @@ -264,7 +264,7 @@ findNearestBetterSessionID = (levelOriginalID, levelMajorVersion, sessionID, ses queryParameters = totalScore: - $gt:opponentSessionTotalScore + $gt: opponentSessionTotalScore _id: $nin: opponentSessionIDs "level.original": levelOriginalID @@ -275,7 +275,9 @@ findNearestBetterSessionID = (levelOriginalID, levelMajorVersion, sessionID, ses team: opposingTeam if opponentSessionTotalScore < 30 - queryParameters["totalScore"]["$gt"] = opponentSessionTotalScore + 2 + # Don't play a ton of matches at low scores--skip some in proportion to how close to 30 we are. + # TODO: this could be made a lot more flexible. + queryParameters["totalScore"]["$gt"] = opponentSessionTotalScore + 2 * (30 - opponentSessionTotalScore) / 20 limitNumber = 1