Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don’t worry, you can still create the pull request.
  • 18 commits
  • 52 files changed
  • 10 commit comments
  • 3 contributors
Showing with 3,354,546 additions and 14 deletions.
  1. +2 −1 .gitignore
  2. +8 −0 LICENSE
  3. +22 −1 README.md
  4. BIN client/audio/sounds/achievement.mp3
  5. BIN client/audio/sounds/achievement.ogg
  6. BIN client/audio/sounds/chat.mp3
  7. BIN client/audio/sounds/chat.ogg
  8. BIN client/audio/sounds/chest.mp3
  9. BIN client/audio/sounds/chest.ogg
  10. BIN client/audio/sounds/death.mp3
  11. BIN client/audio/sounds/death.ogg
  12. BIN client/audio/sounds/firefox.mp3
  13. BIN client/audio/sounds/firefox.ogg
  14. BIN client/audio/sounds/heal.mp3
  15. BIN client/audio/sounds/heal.ogg
  16. BIN client/audio/sounds/hit1.mp3
  17. BIN client/audio/sounds/hit1.ogg
  18. BIN client/audio/sounds/hit2.mp3
  19. BIN client/audio/sounds/hit2.ogg
  20. BIN client/audio/sounds/hurt.mp3
  21. BIN client/audio/sounds/hurt.ogg
  22. BIN client/audio/sounds/kill1.mp3
  23. BIN client/audio/sounds/kill1.ogg
  24. BIN client/audio/sounds/kill2.mp3
  25. BIN client/audio/sounds/kill2.ogg
  26. BIN client/audio/sounds/loot.mp3
  27. BIN client/audio/sounds/loot.ogg
  28. BIN client/audio/sounds/noloot.mp3
  29. BIN client/audio/sounds/noloot.ogg
  30. BIN client/audio/sounds/npc-end.mp3
  31. BIN client/audio/sounds/npc-end.ogg
  32. BIN client/audio/sounds/npc.mp3
  33. BIN client/audio/sounds/npc.ogg
  34. BIN client/audio/sounds/npctalk.mp3
  35. BIN client/audio/sounds/npctalk.ogg
  36. BIN client/audio/sounds/revive.mp3
  37. BIN client/audio/sounds/revive.ogg
  38. BIN client/audio/sounds/teleport.mp3
  39. BIN client/audio/sounds/teleport.ogg
  40. +1 −1 client/maps/world_client.js
  41. +1 −1 client/maps/world_client.json
  42. +14 −0 package.json
  43. +3 −2 server/README.md
  44. +3 −4 server/js/main.js
  45. +4 −4 server/js/metrics.js
  46. +91 −0 tools/maps/README.md
  47. +25 −0 tools/maps/export.py
  48. +62 −0 tools/maps/exportmap.js
  49. +303 −0 tools/maps/processmap.js
  50. +3,353,963 −0 tools/maps/tmx/map.tmx
  51. BIN tools/maps/tmx/mobset.png
  52. +44 −0 tools/maps/tmx2json.py
View
3 .gitignore
@@ -3,5 +3,6 @@ client-build
build.txt
config_build.json
config_local*
-client/audio
+client/audio/music
.DS_Store
+*.swp
View
8 LICENSE
@@ -0,0 +1,8 @@
+* Code is MPL licensed:
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this file,
+You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+* Content is licensed under CC-BY-SA 3.0:
+http://creativecommons.org/licenses/by-sa/3.0/
View
23 README.md
@@ -1,4 +1,25 @@
BrowserQuest
============
-Documentation is located in client and server directories.
+BrowserQuest is a HTML5/JavaScript multiplayer game experiment.
+
+
+Documentation
+-------------
+
+Documentation is located in client and server directories.
+
+
+License
+-------
+
+Code is licensed under MPL 2.0. Content is licensed under CC-BY-SA 3.0.
+See the LICENSE file for details.
+
+
+Credits
+-------
+Created by [Little Workshop](http://www.littleworkshop.fr):
+
+* Franck Lecollinet - [@whatthefranck](http://twitter.com/whatthefranck)
+* Guillaume Lecollinet - [@glecollinet](http://twitter.com/glecollinet)
View
BIN client/audio/sounds/achievement.mp3
Binary file not shown.
View
BIN client/audio/sounds/achievement.ogg
Binary file not shown.
View
BIN client/audio/sounds/chat.mp3
Binary file not shown.
View
BIN client/audio/sounds/chat.ogg
Binary file not shown.
View
BIN client/audio/sounds/chest.mp3
Binary file not shown.
View
BIN client/audio/sounds/chest.ogg
Binary file not shown.
View
BIN client/audio/sounds/death.mp3
Binary file not shown.
View
BIN client/audio/sounds/death.ogg
Binary file not shown.
View
BIN client/audio/sounds/firefox.mp3
Binary file not shown.
View
BIN client/audio/sounds/firefox.ogg
Binary file not shown.
View
BIN client/audio/sounds/heal.mp3
Binary file not shown.
View
BIN client/audio/sounds/heal.ogg
Binary file not shown.
View
BIN client/audio/sounds/hit1.mp3
Binary file not shown.
View
BIN client/audio/sounds/hit1.ogg
Binary file not shown.
View
BIN client/audio/sounds/hit2.mp3
Binary file not shown.
View
BIN client/audio/sounds/hit2.ogg
Binary file not shown.
View
BIN client/audio/sounds/hurt.mp3
Binary file not shown.
View
BIN client/audio/sounds/hurt.ogg
Binary file not shown.
View
BIN client/audio/sounds/kill1.mp3
Binary file not shown.
View
BIN client/audio/sounds/kill1.ogg
Binary file not shown.
View
BIN client/audio/sounds/kill2.mp3
Binary file not shown.
View
BIN client/audio/sounds/kill2.ogg
Binary file not shown.
View
BIN client/audio/sounds/loot.mp3
Binary file not shown.
View
BIN client/audio/sounds/loot.ogg
Binary file not shown.
View
BIN client/audio/sounds/noloot.mp3
Binary file not shown.
View
BIN client/audio/sounds/noloot.ogg
Binary file not shown.
View
BIN client/audio/sounds/npc-end.mp3
Binary file not shown.
View
BIN client/audio/sounds/npc-end.ogg
Binary file not shown.
View
BIN client/audio/sounds/npc.mp3
Binary file not shown.
View
BIN client/audio/sounds/npc.ogg
Binary file not shown.
View
BIN client/audio/sounds/npctalk.mp3
Binary file not shown.
View
BIN client/audio/sounds/npctalk.ogg
Binary file not shown.
View
BIN client/audio/sounds/revive.mp3
Binary file not shown.
View
BIN client/audio/sounds/revive.ogg
Binary file not shown.
View
BIN client/audio/sounds/teleport.mp3
Binary file not shown.
View
BIN client/audio/sounds/teleport.ogg
Binary file not shown.
View
2 client/maps/world_client.js
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
2 client/maps/world_client.json
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
14 package.json
@@ -0,0 +1,14 @@
+{
+ "name": "BrowserQuest"
+ , "version": "0.0.1"
+ , "private": false
+ , "dependencies": {
+ "underscore": ">0"
+ , "log": ">0"
+ , "bison": ">0"
+ , "websocket": ">0"
+ , "websocket-server": ">0"
+ , "sanitizer": ">0"
+ , "memcache": ">0"
+ }
+}
View
5 server/README.md
@@ -9,8 +9,9 @@ The game server currently runs on nodejs v0.4.7 (but should run fine on the late
- websocket
- websocket-server
- sanitizer
+- memcache (only if you want metrics)
-All of them can be installed via `npm install [module_name]`
+All of them can be installed via `npm install -d` (this will install a local copy of all the dependencies in the node_modules directory)
Configuration
@@ -38,4 +39,4 @@ The server has a status URL which can be used as a health check or simply as a w
Send a GET request to: `http://[host]:[port]/status`
-It will return a JSON array containing the number of players in all instanced worlds on this game server.
+It will return a JSON array containing the number of players in all instanced worlds on this game server.
View
7 server/js/main.js
@@ -13,7 +13,7 @@ function main(config) {
worlds = [],
lastTotalPlayers = 0,
checkPopulationInterval = setInterval(function() {
- if(metrics.isReady) {
+ if(metrics && metrics.isReady) {
metrics.getTotalPlayers(function(totalPlayers) {
if(totalPlayers !== lastTotalPlayers) {
lastTotalPlayers = totalPlayers;
@@ -44,7 +44,7 @@ function main(config) {
}
};
- if(config.metrics_enabled) {
+ if(metrics) {
metrics.getOpenWorldCount(function(open_world_count) {
// choose the least populated world among open worlds
world = _.min(_.first(worlds, open_world_count), function(w) { return w.playerCount; });
@@ -78,8 +78,7 @@ function main(config) {
var world = new WorldServer('world'+ (i+1), config.nb_players_per_world, server);
world.run(config.map_filepath);
worlds.push(world);
-
- if(config.metrics_enabled) {
+ if(metrics) {
world.onPlayerAdded(onPopulationChange);
world.onPlayerRemoved(onPopulationChange);
}
View
8 server/js/metrics.js
@@ -1,15 +1,15 @@
var cls = require("./lib/class"),
- _ = require("underscore"),
- memcache = require("memcache");
+ _ = require("underscore");
module.exports = Metrics = Class.extend({
init: function(config) {
var self = this;
this.config = config;
- this.client = new memcache.Client(config.memcached_port, config.memcached_host),
+ this.client = new (require("memcache")).Client(config.memcached_port, config.memcached_host);
this.client.connect();
+
this.isReady = false;
this.client.on('connect', function() {
@@ -73,4 +73,4 @@ module.exports = Metrics = Class.extend({
callback(result);
});
}
-});
+});
View
91 tools/maps/README.md
@@ -0,0 +1,91 @@
+BrowserQuest map exporter
+=========================
+
+***Disclaimer: due to popular demand we are open sourcing this tool, but please be aware that it was never meant to be publicly released. Therefore the code is messy/non-optimized and the exporting process can be very slow with large map files.***
+
+
+Editing the map
+---------------
+
+Install the Tiled editor: http://www.mapeditor.org/
+
+Open the `tmx/map.tmx` file in Tiled and start editing.
+
+**Note:** there currently is no documentation on how to edit BrowserQuest-specific objects/layers in Tiled. Please refer to `tmx/map.tmx` as an example if you want to create your own map.
+
+
+Using the exporter
+------------------
+
+This tool is to be used from the command line after the TMX file has been saved from the Tiled editor.
+
+Note: This tool was written with OSX in mind. If you are using a different OS (eg. Windows), additional/different steps might be required.
+
+**Prerequisites:**
+
+- You need python and nodejs installed.
+- Install pip: http://www.pip-installer.org/en/latest/installing.html
+- Install lxml: `pip install lxml` (preferably within a virtualenv)
+- Optional: Install Growl + growlnotify if you are on OSX.
+
+**Usage:**
+
+1. `cd tools/maps/`
+
+2. `./export.py client` or `./export.py server`
+
+You must run both commands in order to export the client and server map files. There is no one-step export command for both map types yet.
+
+**Warning:** depending on the `.tmx` filesize, the exporting process can take up to several minutes.
+
+
+Things to know
+--------------
+
+The client map export will create two almost identical files: `world_client.js` and `world_client.json`
+These are both required because, depending on the browser, the game will load the map either by using a web worker (loading `world_client.js`), or via Ajax (loading `world_client.json`).
+
+The client map file contains data about terrain tile layers, collision cells, doors, music areas, etc.
+The server map file contains data about static entity spawning points, spawning areas, collision cells, etc.
+
+Depending on what you want to change, it's therefore not always needed to export both maps. Also, each `world_server.json` file change requires a server restart.
+
+**How the exporting process works:**
+
+1. The Tiled map TMX file is converted to a temporary JSON file by `tmx2json.py`.
+2. This file is be processed by `processmap.js` and returned as an object. This object will have different properties depending on whether we are exporting the client or the server map.
+3. The processed map object is saved as the final world map JSON file(s) in the appropriate directories.
+4. The temporary file from step 1. is deleted.
+
+
+**Known bugs:**
+
+ * There currently needs to be an empty layer at the bottom of the Tiled layer stack or else the first terrain layer will be missing.
+ (ie. if you remove the "don't remove this layer" layer from the `map.tmx` file, the 'sand' tiles will be missing on the beach.)
+
+
+Contributing / Ideas for improvement
+------------------------------------
+
+Here are a few ideas for anyone who might want to help make this tool better:
+
+- Remove hard-coded filenames from export.py (eg. `map.tmx`, `world_client.json`) in order to allow easier switching to different map files.
+
+- Fix known bugs (see section above)
+
+- Write documentation on how to use the exporter on Windows.
+
+- Write documentation about map editing in the Tiled editor (ie. editing BrowserQuest-specific properties of doors, chests, spawning areas, etc.)
+
+- Write documentation about the BrowserQuest map JSON format, both for client and server map types.
+
+- Get rid of the `tmx2json.py` step which can currently take up to several minutes. Note: There is a JSON exporter built in Tiled since version 0.8.0 which could be useful. We didn't use it because our tool was written before the 0.8.0 release.
+
+- A complete rewrite of this tool using a custom Tiled plugin would surely be a better approach than the current one. Being able to export directly from Tiled would be much easier to use. Also, the export process is currently too slow.
+
+
+**Additional resources:**
+
+- Tiled editor wiki: https://github.com/bjorn/tiled/wiki
+- TMX map format documentation: https://github.com/bjorn/tiled/wiki/TMX-Map-Format
+
View
25 tools/maps/export.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+import commands
+import sys
+
+SRC_FILE = 'tmx/map.tmx'
+
+TEMP_FILE = SRC_FILE+'.json'
+
+mode = sys.argv[1] if len(sys.argv) > 1 else 'client'
+if mode == 'client':
+ DEST_FILE = '../../client/maps/world_client' # This will save two files (See exportmap.js)
+else:
+ DEST_FILE = '../../server/maps/world_server.json'
+
+# Convert the Tiled TMX file to a temporary JSON file
+print commands.getoutput('./tmx2json.py '+SRC_FILE+' '+TEMP_FILE)
+
+# Map exporting
+print commands.getoutput('./exportmap.js '+TEMP_FILE+' '+DEST_FILE+' '+mode)
+
+# Remove temporary JSON file
+print commands.getoutput('rm '+TEMP_FILE)
+
+# Send a Growl notification when the export process is complete
+print commands.getoutput('growlnotify --appIcon Tiled -name "Map export complete" -m "'+DEST_FILE+' was saved"')
View
62 tools/maps/exportmap.js
@@ -0,0 +1,62 @@
+#!/usr/bin/env node
+
+var util = require('util'),
+ Log = require('log'),
+ path = require("path"),
+ fs = require("fs"),
+ processMap = require('./processmap'),
+ log = new Log(Log.DEBUG);
+
+var source = process.argv[2],
+ destination = process.argv[3],
+ mode = process.argv[4];
+
+if(!source || !destination) {
+ util.puts("Usage : ./exportmap.js map_file json_file [mode]");
+ util.puts("Optional parameter : mode. Values: \"server\" (default) or \"client\".");
+ process.exit(0);
+}
+
+function main() {
+ getTiledJSONmap(source, function(json) {
+ var options = { mode: mode || "server" },
+ map = processMap(json, options);
+
+ var jsonMap = JSON.stringify(map); // Save the processed map object as JSON data
+
+ if(mode === "client") {
+ // map in a .json file for ajax loading
+ fs.writeFile(destination+".json", jsonMap, function(err, file) {
+ log.info("Finished processing map file: "+ destination + ".json was saved.");
+ });
+
+ // map in a .js file for web worker loading
+ jsonMap = "var mapData = "+JSON.stringify(map);
+ fs.writeFile(destination+".js", jsonMap, function(err, file) {
+ log.info("Finished processing map file: "+ destination + ".js was saved.");
+ });
+ } else {
+ fs.writeFile(destination, jsonMap, function(err, file) {
+ log.info("Finished processing map file: "+ destination + " was saved.");
+ });
+ }
+ });
+}
+
+// Loads the temporary JSON Tiled map converted by tmx2json.py
+function getTiledJSONmap(filename, callback) {
+ var self = this;
+
+ path.exists(filename, function(exists) {
+ if(!exists) {
+ log.error(filename + " doesn't exist.")
+ return;
+ }
+
+ fs.readFile(source, function(err, file) {
+ callback(JSON.parse(file.toString()));
+ });
+ });
+}
+
+main();
View
303 tools/maps/processmap.js
@@ -0,0 +1,303 @@
+
+var Log = require('log'),
+ _ = require('underscore'),
+ log = new Log(Log.DEBUG),
+ Types = require("../../shared/js/gametypes");
+
+var map,
+ mode,
+ collidingTiles = {},
+ staticEntities = {},
+ mobsFirstgid;
+
+module.exports = function processMap(json, options) {
+ var self = this,
+ Tiled = json.map,
+ layerIndex = 0,
+ tileIndex = 0,
+ tilesetFilepath = "";
+
+ map = {
+ width: 0,
+ height: 0,
+ collisions: [],
+ doors: [],
+ checkpoints: []
+ };
+ mode = options.mode;
+
+ if(mode === "client") {
+ map.data = [];
+ map.high = [];
+ map.animated = {};
+ map.blocking = [];
+ map.plateau = [];
+ map.musicAreas = [];
+ }
+ if(mode === "server") {
+ map.roamingAreas = [];
+ map.chestAreas = [];
+ map.staticChests = [];
+ map.staticEntities = {};
+ }
+
+ log.info("Processing map info...");
+ map.width = Tiled.width;
+ map.height = Tiled.height;
+ map.tilesize = Tiled.tilewidth;
+
+ // Tile properties (collision, z-index, animation length...)
+ var tileProperties;
+ var handleProp = function(property, id) {
+ if(property.name === "c") {
+ collidingTiles[id] = true;
+ }
+
+ if(mode === "client") {
+ if(property.name === "v") {
+ map.high.push(id);
+ }
+ if(property.name === "length") {
+ if(!map.animated[id]) {
+ map.animated[id] = {};
+ }
+ map.animated[id].l = property.value;
+ }
+ if(property.name === "delay") {
+ if(!map.animated[id]) {
+ map.animated[id] = {};
+ }
+ map.animated[id].d = property.value;
+ }
+ }
+ }
+
+ if(Tiled.tileset instanceof Array) {
+ _.each(Tiled.tileset, function(tileset) {
+ if(tileset.name === "tilesheet") {
+ log.info("Processing terrain properties...");
+ tileProperties = tileset.tile;
+ for(var i=0; i < tileProperties.length; i += 1) {
+ var property = tileProperties[i].properties.property;
+ var tilePropertyId = tileProperties[i].id + 1;
+ if(property instanceof Array) {
+ for(var pi=0; pi < property.length; pi += 1) {
+ handleProp(property[pi], tilePropertyId);
+ }
+ } else {
+ handleProp(property, tilePropertyId);
+ }
+ }
+ }
+ else if(tileset.name === "Mobs" && mode === "server") {
+ log.info("Processing static entity properties...");
+ mobsFirstgid = tileset.firstgid;
+ _.each(tileset.tile, function(p) {
+ var property = p.properties.property,
+ id = p.id + 1;
+
+ if(property.name === "type") {
+ staticEntities[id] = property.value;
+ }
+ });
+ }
+ });
+ } else {
+ log.error("A tileset is missing");
+ }
+
+
+ for(var i=0; i < Tiled.objectgroup.length; i += 1) {
+ var group = Tiled.objectgroup[i];
+ if(group.name === 'doors') {
+ var doors = group.object;
+ log.info("Processing doors...");
+ for(var j=0; j < doors.length; j += 1) {
+ map.doors[j] = {
+ x: doors[j].x / map.tilesize,
+ y: doors[j].y / map.tilesize,
+ p: (doors[j].type === 'portal') ? 1 : 0,
+ }
+ var doorprops = doors[j].properties.property;
+ for(var k=0; k < doorprops.length; k += 1) {
+ map.doors[j]['t'+doorprops[k].name] = doorprops[k].value;
+ }
+ }
+ }
+ }
+
+ // Object layers
+ _.each(Tiled.objectgroup, function(objectlayer) {
+ if(objectlayer.name === "roaming" && mode === "server") {
+ log.info("Processing roaming areas...");
+ var areas = objectlayer.object;
+
+ for(var i=0; i < areas.length; i += 1) {
+ if(areas[i].properties) {
+ var nb = areas[i].properties.property.value;
+ }
+
+ map.roamingAreas[i] = { id: i,
+ x: areas[i].x / 16,
+ y: areas[i].y / 16,
+ width: areas[i].width / 16,
+ height: areas[i].height / 16,
+ type: areas[i].type,
+ nb: nb
+ };
+ }
+ }
+ else if(objectlayer.name === "chestareas" && mode === "server") {
+ log.info("Processing chest areas...");
+ _.each(objectlayer.object, function(area) {
+ var chestArea = {
+ x: area.x / map.tilesize,
+ y: area.y / map.tilesize,
+ w: area.width / map.tilesize,
+ h: area.height / map.tilesize
+ };
+ _.each(area.properties.property, function(prop) {
+ if(prop.name === 'items') {
+ chestArea['i'] = _.map(prop.value.split(','), function(name) {
+ return Types.getKindFromString(name);
+ });
+ } else {
+ chestArea['t'+prop.name] = prop.value;
+ }
+ });
+ map.chestAreas.push(chestArea);
+ });
+ }
+ else if(objectlayer.name === "chests" && mode === "server") {
+ log.info("Processing static chests...");
+ _.each(objectlayer.object, function(chest) {
+ var items = chest.properties.property.value;
+ var newChest = {
+ x: chest.x / map.tilesize,
+ y: chest.y / map.tilesize,
+ i: _.map(items.split(','), function(name) {
+ return Types.getKindFromString(name);
+ })
+ };
+ map.staticChests.push(newChest);
+ });
+ }
+ else if(objectlayer.name === "music" && mode === "client") {
+ log.info("Processing music areas...");
+ _.each(objectlayer.object, function(music) {
+ var musicArea = {
+ x: music.x / map.tilesize,
+ y: music.y / map.tilesize,
+ w: music.width / map.tilesize,
+ h: music.height / map.tilesize,
+ id: music.properties.property.value
+ };
+ map.musicAreas.push(musicArea);
+ });
+ }
+ else if(objectlayer.name === "checkpoints") {
+ log.info("Processing check points...");
+ var count = 0;
+ _.each(objectlayer.object, function(checkpoint) {
+ var cp = {
+ id: ++count,
+ x: checkpoint.x / map.tilesize,
+ y: checkpoint.y / map.tilesize,
+ w: checkpoint.width / map.tilesize,
+ h: checkpoint.height / map.tilesize
+ };
+ if(mode === "server") {
+ cp.s = checkpoint.type ? 1 : 0;
+ }
+ map.checkpoints.push(cp);
+ });
+ }
+ });
+
+ // Layers
+ if(Tiled.layer instanceof Array) {
+ for(var i=Tiled.layer.length - 1; i > 0; i -= 1) {
+ processLayer(Tiled.layer[i]);
+ }
+ } else {
+ processLayer(Tiled.layer);
+ }
+
+ if(mode === "client") {
+ // Set all undefined tiles to 0
+ for(var i=0, max=map.data.length; i < max; i+=1) {
+ if(!map.data[i]) {
+ map.data[i] = 0;
+ }
+ }
+ }
+
+ return map;
+};
+
+var processLayer = function processLayer(layer) {
+ if(mode === "server") {
+ // Mobs
+ if(layer.name === "entities") {
+ log.info("Processing positions of static entities ...");
+ var tiles = layer.data.tile;
+
+ for(var j=0; j < tiles.length; j += 1) {
+ var gid = tiles[j].gid - mobsFirstgid + 1;
+ if(gid && gid > 0) {
+ map.staticEntities[j] = staticEntities[gid];
+ }
+ }
+ }
+ }
+
+ var tiles = layer.data.tile;
+
+ if(mode === "client" && layer.name === "blocking") {
+ log.info("Processing blocking tiles...");
+ for(var i=0; i < tiles.length; i += 1) {
+ var gid = tiles[i].gid;
+
+ if(gid && gid > 0) {
+ map.blocking.push(i);
+ }
+ }
+ }
+ else if(mode === "client" && layer.name === "plateau") {
+ log.info("Processing plateau tiles...");
+ for(var i=0; i < tiles.length; i += 1) {
+ var gid = tiles[i].gid;
+
+ if(gid && gid > 0) {
+ map.plateau.push(i);
+ }
+ }
+ }
+ else if(layer.visible !== 0 && layer.name !== "entities") {
+ log.info("Processing layer: "+ layer.name);
+
+ for(var j=0; j < tiles.length; j += 1) {
+ var gid = tiles[j].gid;
+
+ if(mode === "client") {
+ // Set tile gid in the tilesheet
+ if(gid > 0) {
+ if(map.data[j] === undefined) {
+ map.data[j] = gid;
+ }
+ else if(map.data[j] instanceof Array) {
+ map.data[j].unshift(gid);
+ }
+ else {
+ map.data[j] = [gid, map.data[j]];
+ }
+ }
+ }
+
+ // Colliding tiles
+ if(gid in collidingTiles) {
+ map.collisions.push(j);
+ }
+ }
+ }
+}
View
3,353,963 tools/maps/tmx/map.tmx
3,353,963 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
BIN tools/maps/tmx/mobset.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
44 tools/maps/tmx2json.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+import sys
+from lxml import etree
+import json
+
+tmx = open(sys.argv[1])
+dest = open(sys.argv[2], 'w')
+res = {}
+
+root = etree.parse(tmx).getroot()
+el = root
+
+def process(el, tagname):
+ attrs = dict(el.attrib)
+ for a in attrs.keys():
+ if attrs[a].isdigit():
+ attrs[a] = int(attrs[a])
+
+ children = el.getchildren()
+
+ if len(children) > 1:
+ sibs = {}
+ for c in children:
+ if c.tag not in sibs:
+ sibs[c.tag] = []
+ sibs[c.tag].append(process(c, False))
+ for k in sibs.keys():
+ attrs.update({k: sibs[k]})
+ else:
+ for c in children:
+ attrs.update(process(c, True))
+
+ if tagname:
+ return {el.tag: attrs}
+ else:
+ return attrs
+
+res = process(el, True)
+
+dest.write(json.dumps(res))
+tmx.close()
+dest.close()
+
+print "Finished converting TMX to JSON."

Showing you all comments on commits in this comparison.

@mkrecny

Thanks for adding this. I'm going to be honest and say that i don't really have the legal wherewithal to comprehend this document. What's the short version? Can we host modified versions of BrowserQuest for profit?

@JacobHacker

The basics are, if you add a source file you can license it as you wish, even proprietary. You may sell it as long as you have a way someone can download the source code, and you make this way know the person you're selling it to.

However currently there's only a license for the code.
https://github.com/mozilla/BrowserQuest/issues/53

@mkrecny

Okay cool - what exactly do you mean by 'add a source file'? Does refactoring existing files count?

@JacobHacker

It seems, (and should you sell this you will definitely want to check) that source code you contribute is yours, but modifying a file does not make it yours.

e.g. If I edit source A it is still under MPL, but if I add source file B to the project, without using any code from the project, it is mine.

@mkrecny

Meaning that source B doesn't depend on any existing project code?

@JacobHacker

Yes, exactly, if you write all of source B, it is yours to license as you wish. Also the license is fairly strict in saying that you must have the source code readily available if you sell it in executable form (or charge people to use it in their browser).

@lexcture

'Tmx/map.tmx

@Justbod

Hey! I'm just and i'm 13 years old. I have a website and wanna make a virtual world. Can i use your source to make some things?

@nickdesaulniers

Hello young hacker! Welcome! Indeed you may; take a look at the software license for this project to see what you have the right to do with it. Go forth and with this power change the world!

@Justbod

Thanks! :)

Something went wrong with that request. Please try again.