Index: binaries/data/mods/public/globalscripts/Templates.js
===================================================================
--- binaries/data/mods/public/globalscripts/Templates.js	(revision 18200)
+++ binaries/data/mods/public/globalscripts/Templates.js	(working copy)
@@ -142,13 +142,15 @@
 		};
 
 		// optional properties
-		if (template.BuildRestrictions.Distance)
+		if (template.BuildRestrictions.Density)
 		{
-			ret.buildRestrictions.distance = {
-				"fromClass": template.BuildRestrictions.Distance.FromClass,
+			ret.buildRestrictions.density = {
+				"fromClass": template.BuildRestrictions.Density.FromClass,
 			};
-			if (template.BuildRestrictions.Distance.MinDistance) ret.buildRestrictions.distance.min = +template.BuildRestrictions.Distance.MinDistance;
-			if (template.BuildRestrictions.Distance.MaxDistance) ret.buildRestrictions.distance.max = +template.BuildRestrictions.Distance.MaxDistance;
+			if (template.BuildRestrictions.Density.MinEntity)
+				ret.buildRestrictions.density.min = +template.BuildRestrictions.Density.MinEntity;
+			if (template.BuildRestrictions.Density.MaxEntity)
+				ret.buildRestrictions.density.max = +template.BuildRestrictions.Density.MaxEntity;
 		}
 	}
 
Index: binaries/data/mods/public/gui/session/input.js
===================================================================
--- binaries/data/mods/public/gui/session/input.js	(revision 18200)
+++ binaries/data/mods/public/gui/session/input.js	(working copy)
@@ -100,7 +100,7 @@
 	{
 		if (placementSupport.template && placementSupport.position)
 		{
-			var result = Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {
+			let result = Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {
 				"template": placementSupport.template,
 				"x": placementSupport.position.x,
 				"z": placementSupport.position.z,
@@ -160,12 +160,33 @@
 				true  // include foundations
 			);
 
-			return Engine.GuiInterfaceCall("SetWallPlacementPreview", {
+			let result =  Engine.GuiInterfaceCall("SetWallPlacementPreview", {
 				"wallSet": placementSupport.wallSet,
 				"start": placementSupport.position,
 				"end": placementSupport.wallEndPosition,
 				"snapEntities": placementSupport.wallSnapEntities,	// snapping entities (towers) for starting a wall segment
 			});
+
+			// Show placement info tooltip if invalid position
+			placementSupport.tooltipError = !result.success;
+			placementSupport.tooltipMessage = "";
+			if (!result.success)
+			{
+				if (result.message && result.parameters)
+				{
+					let message = result.message;
+					if (result.translateMessage)
+						if (result.pluralMessage)
+							message = translatePlural(result.message, result.pluralMessage, result.pluralCount);
+						else
+							message = translate(message);
+					let parameters = result.parameters;
+					if (result.translateParameters)
+						translateObjectKeys(parameters, result.translateParameters);
+					placementSupport.tooltipMessage = sprintf(message, parameters);
+				}
+			}
+			return result;
 		}
 	}
 
Index: binaries/data/mods/public/simulation/ai/common-api/entity.js
===================================================================
--- binaries/data/mods/public/simulation/ai/common-api/entity.js	(revision 18200)
+++ binaries/data/mods/public/simulation/ai/common-api/entity.js	(working copy)
@@ -485,10 +485,10 @@
 		return +this.get("Cost/BuildTime");
 	},
 
-	buildDistance: function() {
-		if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Distance"))
+	buildDensity: function() {
+		if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Density"))
 			return undefined;
-		return this.get("BuildRestrictions/Distance");
+		return this.get("BuildRestrictions/Density");
 	},
 
 	buildPlacementType: function() {
Index: binaries/data/mods/public/simulation/ai/common-api/map-module.js
===================================================================
--- binaries/data/mods/public/simulation/ai/common-api/map-module.js	(revision 18200)
+++ binaries/data/mods/public/simulation/ai/common-api/map-module.js	(working copy)
@@ -121,7 +121,7 @@
 				let r2 = dx*dx + dy*dy;
 				if (r2 < maxDist2)
 				{
-					let w = x + y * this.width;				
+					let w = x + y * this.width;
 					if (this.map[w] + strength < 0)
 						this.map[w] = 0;
 					else if (this.map[w] + strength > this.maxVal)
@@ -132,6 +132,28 @@
 			}
 		}
 	}
+	else if (type === 'inverseConstant' || type === "inverseConstant") // TODO needed for other cases too?
+	{
+		for (let y = y0; y < y1; ++y)
+		{
+			let dy = y - cy;
+			for (let x = x0; x < x1; ++x)
+			{
+				let dx = x - cx;
+				let r2 = dx*dx + dy*dy;
+				if (r2 > maxDist2)
+				{
+					let w = x + y * this.width;
+					if (this.map[w] + strength < 0)
+						this.map[w] = 0;
+					else if (this.map[w] + strength > this.maxVal)
+						this.map[w] = this.maxVal;	// avoids overflow.
+					else
+						this.map[w] += strength;
+				}
+			}
+		}
+	}
 };
 
 m.Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type)
Index: binaries/data/mods/public/simulation/ai/petra/mapModule.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/mapModule.js	(revision 18200)
+++ binaries/data/mods/public/simulation/ai/petra/mapModule.js	(working copy)
@@ -84,24 +84,44 @@
 	var map = new API3.Map(gameState.sharedScript, "passability", obstructionTiles);
 	map.setMaxVal(255);
 
-	if (template && template.buildDistance())
+	if (template && template.buildDensity())
 	{
-		let minDist = +template.buildDistance().MinDistance;
-		let fromClass = template.buildDistance().FromClass;
-		if (minDist && fromClass)
+		let buildDensity = template.buildDensity();
+		if (buildDensity)
 		{
+			let Dist = +buildDensity.Distance;
+			let fromClass = buildDensity.FromClass;
 			let cellSize = passabilityMap.cellSize;
-			let cellDist = 1 + minDist / cellSize;
+			let cellDist = 1 + Dist / cellSize;
 			let structures = gameState.getOwnStructures().filter(API3.Filters.byClass(fromClass));
-			for (let ent of structures.values())
+			// TODO the following will have problems when both MaxEntity and MinEntity are specified
+			// and that is allowed in template. Probably it needs to get some more efficient too. 
+			if (buildDensity.MaxEntity)
 			{
-				if (!ent.position())
-					continue;
-				let pos = ent.position();
-				let x = Math.round(pos[0] / cellSize);
-				let z = Math.round(pos[1] / cellSize);
-				map.addInfluence(x, z, cellDist, -255, "constant");
+				let influence = Math.floor(-255 / (+buildDensity.MaxEntity + 1));
+				for (let ent of structures.values())
+				{
+					if (!ent.position())
+						continue;
+					let pos = ent.position();
+					let x = Math.round(pos[0] / cellSize);
+					let z = Math.round(pos[1] / cellSize);
+					map.addInfluence(x, z, cellDist, influence, "constant");
+				}
 			}
+			if (buildDensity.MinEntity)
+			{
+				let influence = Math.floor(-255 / (+buildDensity.MinEntity));
+				for (let ent of structures.values())
+				{
+					if (!ent.position())
+						continue;
+					let pos = ent.position();
+					let x = Math.round(pos[0] / cellSize);
+					let z = Math.round(pos[1] / cellSize);
+					map.addInfluence(x, z, cellDist, influence, "inverseConstant");
+				}
+			}
 		}
 	}
 
Index: binaries/data/mods/public/simulation/components/BuildRestrictions.js
===================================================================
--- binaries/data/mods/public/simulation/components/BuildRestrictions.js	(revision 18200)
+++ binaries/data/mods/public/simulation/components/BuildRestrictions.js	(working copy)
@@ -7,10 +7,12 @@
 			"<PlacementType>land</PlacementType>" +
 			"<Territory>own</Territory>" +
 			"<Category>Special</Category>" +
-			"<Distance>" +
+			"<Density>" +
 				"<FromClass>CivilCentre</FromClass>" +
-				"<MaxDistance>40</MaxDistance>" +
-			"</Distance>" +
+				"<Distance>200</Distance>" +
+				"<MaxEntity>3</MaxEntity>" +
+				"<MinEntity>1</MinEntity>" +
+			"</Density>" +
 		"</BuildRestrictions>" +
 	"</a:example>" +
 	"<element name='PlacementType' a:help='Specifies the terrain type restriction for this building.'>" +
@@ -32,17 +34,18 @@
 			"</oneOrMore>" +
 		"</list>" +
 	"</element>" +
-	"<element name='Category' a:help='Specifies the category of this building, for satisfying special constraints. Choices include: CivilCentre, House, DefenseTower, Farmstead, Market, Barracks, Dock, Fortress, Field, Temple, Wall, Fence, Storehouse, Stoa, Resource, Special, Wonder, Apadana, Embassy, Monument'>" +
+	"<element name='Category' a:help='Specifies the category of this building, for satisfying special constraints. Choices include: Apadana, Barracks, CivilCentre, DefenseTower, Dock, Embassy, Farmstead, Field, Fence, Fortress, House, Market, Monument, Resource, Special, Stoa, Storehouse, Temple, Tower, Wall, WallTower, Wonder'>" +
 		"<text/>" +
 	"</element>" +
 	"<optional>" +
-		"<element name='Distance' a:help='Specifies distance restrictions on this building, relative to buildings from the given category.'>" +
+		"<element name='Density' a:help='Specifies distance restrictions on this building, relative to buildings from the given category.'>" +
 			"<interleave>" +
 				"<element name='FromClass'>" +
 					"<text/>" +
 				"</element>" +
-				"<optional><element name='MinDistance'><data type='positiveInteger'/></element></optional>" +
-				"<optional><element name='MaxDistance'><data type='positiveInteger'/></element></optional>" +
+				"<element name='Distance'><data type='positiveInteger'/></element>" +
+				"<optional><element name='MinEntity'><data type='nonNegativeInteger'/></element></optional>" +
+				"<optional><element name='MaxEntity'><data type='nonNegativeInteger'/></element></optional>" +
 			"</interleave>" +
 		"</element>" +
 	"</optional>";
@@ -50,6 +53,11 @@
 BuildRestrictions.prototype.Init = function()
 {
 	this.territories = this.template.Territory.split(/\s+/);
+	if (this.template.Density)
+	{
+		this.minEntity = +(this.template.Density.MinEntity || 0);
+		this.maxEntity = +(this.template.Density.MaxEntity || Infinity);
+	}
 };
 
 /**
@@ -60,7 +68,7 @@
  *		b. On valid terrain, based on passability class
  *	3. Territory type is allowed (see note below)
  *	4. Dock is on shoreline and facing into water
- *	5. Distance constraints satisfied
+ *	5. Density constraints satisfied
  *
  * Returns result object:
  * 	{
@@ -79,10 +87,10 @@
  */
 BuildRestrictions.prototype.CheckPlacement = function()
 {
-	var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
-	var name = cmpIdentity ? cmpIdentity.GetGenericName() : "Building";
+	let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
+	let name = cmpIdentity ? cmpIdentity.GetGenericName() : "Building";
 
-	var result = {
+	let result = {
 		"success": false,
 		"message": markForTranslation("%(name)s cannot be built due to unknown error"),
 		"parameters": {
@@ -93,17 +101,16 @@
 	};
 
 	// TODO: AI has no visibility info
-	var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
+	let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
 	if (!cmpPlayer.IsAI())
 	{
 		// Check whether it's in a visible or fogged region
-		var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
-		var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+		let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+		let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
 		if (!cmpRangeManager || !cmpOwnership)
 			return result; // Fail
 
-		var explored = (cmpRangeManager.GetLosVisibility(this.entity, cmpOwnership.GetOwner()) != "hidden");
-		if (!explored)
+		if (cmpRangeManager.GetLosVisibility(this.entity, cmpOwnership.GetOwner()) == "hidden")
 		{
 			result.message = markForTranslation("%(name)s cannot be built in unexplored area");
 			return result; // Fail
@@ -111,7 +118,7 @@
 	}
 
 	// Check obstructions and terrain passability
-	var passClassName = "";
+	let passClassName = "";
 	switch (this.template.PlacementType)
 	{
 	case "shore":
@@ -129,20 +136,15 @@
 		passClassName = "building-land";
 	}
 
-	var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
+	let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
 	if (!cmpObstruction)
 		return result; // Fail
 
-
+		// for walls, only test the center point
 	if (this.template.Category == "Wall")
-	{
-		// for walls, only test the center point
 		var ret = cmpObstruction.CheckFoundation(passClassName, true);
-	}
 	else
-	{
 		var ret = cmpObstruction.CheckFoundation(passClassName, false);
-	}
 
 	if (ret != "success")
 	{
@@ -152,9 +154,11 @@
 		case "fail_no_obstruction":
 			error("CheckPlacement: Error returned from CheckFoundation");
 			break;
+
 		case "fail_obstructs_foundation":
 			result.message = markForTranslation("%(name)s cannot be built on another building or resource");
 			break;
+
 		case "fail_terrain_class":
 			// TODO: be more specific and/or list valid terrain?
 			result.message = markForTranslation("%(name)s cannot be built on invalid terrain");
@@ -163,21 +167,18 @@
 	}
 
 	// Check territory restrictions
-	var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
-	var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
-	var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
-	if (!(cmpTerritoryManager && cmpPlayer && cmpPosition && cmpPosition.IsInWorld()))
+	let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
+	let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
+	let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
+	if (!cmpTerritoryManager || !cmpPlayer || !cmpPosition || !cmpPosition.IsInWorld())
 		return result;	// Fail
 
-	var pos = cmpPosition.GetPosition2D();
-	var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y);
-	var isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y);
-	var isOwn = tileOwner == cmpPlayer.GetPlayerID();
-	var isMutualAlly = cmpPlayer.IsExclusiveMutualAlly(tileOwner);
-	var isNeutral = tileOwner == 0;
+	let pos = cmpPosition.GetPosition2D();
+	let tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y);
+	let isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y);
 
-	var invalidTerritory = "";
-	if (isOwn)
+	let invalidTerritory = "";
+	if (tileOwner == cmpPlayer.GetPlayerID()) // Own territory
 	{
 		if (!this.HasTerritory("own"))
 			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
@@ -186,7 +187,7 @@
 			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
 			invalidTerritory = markForTranslationWithContext("Territory type", "unconnected own");
 	}
-	else if (isMutualAlly)
+	else if (cmpPlayer.IsExclusiveMutualAlly(tileOwner))
 	{
 		if (!this.HasTerritory("ally"))
 			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
@@ -195,7 +196,7 @@
 			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
 			invalidTerritory = markForTranslationWithContext("Territory type", "unconnected allied");
 	}
-	else if (isNeutral)
+	else if (tileOwner == 0) // Neutral territory
 	{
 		if (!this.HasTerritory("neutral"))
 			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
@@ -227,26 +228,26 @@
 		//		1. ships can be spawned "nearby"
 		//		2. builders can pass the terrain where the dock is placed (don't worry about paths)
 		//	so it's correct even if the criteria changes for these units
-		var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
+		let cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
 		if (!cmpFootprint)
 			return result;	// Fail
 
 		// Get building's footprint
-		var shape = cmpFootprint.GetShape();
-		var halfSize = 0;
+		let shape = cmpFootprint.GetShape();
+		let halfSize = 0;
 		if (shape.type == "square")
-			halfSize = shape.depth/2;
+			halfSize = shape.depth / 2;
 		else if (shape.type == "circle")
 			halfSize = shape.radius;
 
-		var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
-		var cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);
+		let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
+		let cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);
 		if (!cmpTerrain || !cmpWaterManager)
 			return result;	// Fail
 
-		var ang = cmpPosition.GetRotation().y;
-		var sz = halfSize * Math.sin(ang);
-		var cz = halfSize * Math.cos(ang);
+		let ang = cmpPosition.GetRotation().y;
+		let sz = halfSize * Math.sin(ang);
+		let cz = halfSize * Math.cos(ang);
 		if ((cmpWaterManager.GetWaterLevel(pos.x + sz, pos.y + cz) - cmpTerrain.GetGroundLevel(pos.x + sz, pos.y + cz)) < 1.0 // front
 			|| (cmpWaterManager.GetWaterLevel(pos.x - sz, pos.y - cz) - cmpTerrain.GetGroundLevel(pos.x - sz, pos.y - cz)) > 2.0) // back
 		{
@@ -256,61 +257,55 @@
 	}
 
 	// Check distance restriction
-	if (this.template.Distance)
+	if (this.template.Density)
 	{
-		var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
-		var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
-		var cat = this.template.Distance.FromClass;
+		let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+		let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
+		let cat = this.template.Density.FromClass;
+		let dist = +this.template.Density.Distance
 
-		var filter = function(id)
+		let filter = function(id)
 		{
-			var cmpIdentity = Engine.QueryInterface(id, IID_Identity);
+			let cmpIdentity = Engine.QueryInterface(id, IID_Identity);
 			return cmpIdentity.GetClassesList().indexOf(cat) > -1;
 		};
 		
-		if (this.template.Distance.MinDistance)
+		let nearEnts = cmpRangeManager.ExecuteQuery(this.entity, 0, dist, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).filter(filter);
+
+		if (nearEnts.length > this.maxEntity)
 		{
-			var dist = +this.template.Distance.MinDistance;
-			var nearEnts = cmpRangeManager.ExecuteQuery(this.entity, 0, dist, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).filter(filter);
-			if (nearEnts.length)
-			{
-				var result = markForPluralTranslation(
-					"%(name)s too close to a %(category)s, must be at least %(distance)s meter away",
-					"%(name)s too close to a %(category)s, must be at least %(distance)s meters away",
-					+this.template.Distance.MinDistance);
+			let result = markForPluralTranslation(
+				"%(name)s too close to a %(category)s, must be at least %(distance)s meter away",
+				"%(name)s too close to a %(category)s, must be at least %(distance)s meters away",
+				+this.template.Density.Distance);
 
-				result.success = false;
-				result.translateMessage = true;
-				result.parameters = {
-					"name": name,
-					"category": cat,
-					"distance": this.template.Distance.MinDistance
-				};
-				result.translateParameters = ["name", "category"];
-				return result;  // Fail
-			}
+			result.success = false;
+			result.translateMessage = true;
+			result.parameters = {
+				"name": name,
+				"category": cat,
+				"distance": this.template.Density.Distance
+			};
+			result.translateParameters = ["name", "category"];
+			return result;  // Fail
 		}
-		if (this.template.Distance.MaxDistance)
+
+		if (nearEnts.length < this.minEntity)
 		{
-			var dist = +this.template.Distance.MaxDistance;
-			var nearEnts = cmpRangeManager.ExecuteQuery(this.entity, 0, dist, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).filter(filter);
-			if (!nearEnts.length)
-			{
-				var result = markForPluralTranslation(
-					"%(name)s too far from a %(category)s, must be within %(distance)s meter",
-					"%(name)s too far from a %(category)s, must be within %(distance)s meters",
-					+this.template.Distance.MinDistance);
+			let result = markForPluralTranslation(
+				"%(name)s too far from a %(category)s, must be within %(distance)s meter",
+				"%(name)s too far from a %(category)s, must be within %(distance)s meters",
+				+this.template.Density.Distance);
 
-				result.success = false;
-				result.translateMessage = true;
-				result.parameters = {
-					"name": name,
-					"category": cat,
-					"distance": this.template.Distance.MaxDistance
-				};
-				result.translateParameters = ["name", "category"];
-				return result;	// Fail
-			}
+			result.success = false;
+			result.translateMessage = true;
+			result.parameters = {
+				"name": name,
+				"category": cat,
+				"distance": this.template.Density.Distance
+			};
+			result.translateParameters = ["name", "category"];
+			return result;	// Fail
 		}
 	}
 
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(revision 18200)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(working copy)
@@ -988,13 +988,13 @@
  */
 GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd)
 {
-	let result = {
-		"success": false,
-		"message": "",
-		"parameters": {},
-		"translateMessage": false,
-		"translateParameters": [],
-	};
+    let result = {
+        "success": false,
+        "message": "",
+        "parameters": {},
+        "translateMessage": false,
+        "translateParameters": [],
+    };
 
 	// See if we're changing template
 	if (!this.placementEntity || this.placementEntity[0] != cmd.template)
@@ -1244,6 +1244,7 @@
 	// calculate wall placement and position preview entities
 
 	let result = {
+		"success": true,
 		"pieces": [],
 		"cost": { "food": 0, "wood": 0, "stone": 0, "metal": 0, "population": 0, "populationBonus": 0, "time": 0 },
 	};
@@ -1484,9 +1485,18 @@
 				continue;
 			}
 
-			// TODO: Handle results of CheckPlacement
-			validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success);
+			let placementResult = cmpBuildRestrictions.CheckPlacement()
+			if (!placementResult.success)
+			{
+				result.success = false;
+				result.message = placementResult.message;
+				result.parameters = placementResult.parameters;
+				result.translateMessage = placementResult.translateMessage;
+				result.translateParameters = placementResult.translateParameters;
+			}
 
+			validPlacement = (cmpBuildRestrictions && placementResult.success);
+
 			// If a wall piece has two control groups, it's likely a segment that spans
 			// between two existing towers. To avoid placing a duplicate wall segment,
 			// check for collisions with entities that share both control groups.
@@ -1550,7 +1560,7 @@
 	// If any were entities required to build the wall, but none of them could be validly positioned, return failure
 	// (see method-level documentation).
 	if (numRequiredPieces > 0 && result.pieces.length == 0)
-		return false;
+		return result;
 
 	if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY)
 		result.startSnappedEnt = start.snappedEnt;
Index: binaries/data/mods/public/simulation/helpers/Walls.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Walls.js	(revision 18200)
+++ binaries/data/mods/public/simulation/helpers/Walls.js	(working copy)
@@ -20,24 +20,24 @@
  */
 function GetWallPlacement(placementData, wallSet, start, end)
 {
-	var result = [];
+	let result = [];
 	
-	var candidateSegments = [
-		{"template": wallSet.templates.long,   "len": placementData[wallSet.templates.long].templateData.wallPiece.length},
-		{"template": wallSet.templates.medium, "len": placementData[wallSet.templates.medium].templateData.wallPiece.length},
-		{"template": wallSet.templates.short,  "len": placementData[wallSet.templates.short].templateData.wallPiece.length},
+	let candidateSegments = [
+		{ "template": wallSet.templates.long,   "len": placementData[wallSet.templates.long].templateData.wallPiece.length },
+		{ "template": wallSet.templates.medium, "len": placementData[wallSet.templates.medium].templateData.wallPiece.length },
+		{ "template": wallSet.templates.short,  "len": placementData[wallSet.templates.short].templateData.wallPiece.length },
 	];
 	
-	var towerWidth = placementData[wallSet.templates.tower].templateData.wallPiece.length;
+	let towerWidth = placementData[wallSet.templates.tower].templateData.wallPiece.length;
 	
-	var dir = {"x": end.pos.x - start.pos.x, "z": end.pos.z - start.pos.z};
-	var len = Math.sqrt(dir.x * dir.x + dir.z * dir.z);
+	let dir = { "x": end.pos.x - start.pos.x, "z": end.pos.z - start.pos.z };
+	let len = Math.sqrt(dir.x * dir.x + dir.z * dir.z);
 	
 	// we'll need room for at least our starting and ending towers to fit next to eachother
 	if (len <= towerWidth)
 		return result;
 	
-	var placement = GetWallSegmentsRec(len, candidateSegments, wallSet.minTowerOverlap, wallSet.maxTowerOverlap, towerWidth, 0, []);
+	let placement = GetWallSegmentsRec(len, candidateSegments, wallSet.minTowerOverlap, wallSet.maxTowerOverlap, towerWidth, 0, []);
 	
 	// TODO: make sure intermediate towers are spaced out far enough for their obstructions to not overlap, implying that
 	// tower's wallpiece lengths should be > their obstruction width, which is undesirable because it prevents towers with
@@ -44,36 +44,36 @@
 	// wide bases
 	if (placement)
 	{
-		var placedEntities = placement.segments; // list of chosen candidate segments
-		var r = placement.r; // remaining distance to target without towers (must be <= (N-1) * towerWidth)
-		var s = r / (2 * placedEntities.length); // spacing
+		let placedEntities = placement.segments; // list of chosen candidate segments
+		let r = placement.r; // remaining distance to target without towers (must be <= (N-1) * towerWidth)
+		let s = r / (2 * placedEntities.length); // spacing
 		
-		var dirNormalized = {"x": dir.x / len, "z": dir.z / len};
-		var angle = -Math.atan2(dir.z, dir.x);    // angle of this wall segment (relative to world-space X/Z axes)
+		let dirNormalized = { "x": dir.x / len, "z": dir.z / len };
+		let angle = -Math.atan2(dir.z, dir.x);    // angle of this wall segment (relative to world-space X/Z axes)
 		
-		var progress = 0;
-		for (var i = 0; i < placedEntities.length; i++)
+		let progress = 0;
+		for (let i = 0; i < placedEntities.length; i++)
 		{
-			var placedEntity = placedEntities[i];
-			var targetX = start.pos.x + (progress + s + placedEntity.len/2) * dirNormalized.x;
-			var targetZ = start.pos.z + (progress + s + placedEntity.len/2) * dirNormalized.z;
+			let placedEntity = placedEntities[i];
+			let targetX = start.pos.x + (progress + s + placedEntity.len/2) * dirNormalized.x;
+			let targetZ = start.pos.z + (progress + s + placedEntity.len/2) * dirNormalized.z;
 			
 			result.push({
 				"template": placedEntity.template,
-				"pos": {"x": targetX, "z": targetZ},
+				"pos": { "x": targetX, "z": targetZ },
 				"angle": angle,
 			});
 			
 			if (i < placedEntities.length - 1)
 			{
-				var towerX = start.pos.x + (progress + placedEntity.len + 2*s) * dirNormalized.x;
-				var towerZ = start.pos.z + (progress + placedEntity.len + 2*s) * dirNormalized.z;
+				let towerX = start.pos.x + (progress + placedEntity.len + 2*s) * dirNormalized.x;
+				let towerZ = start.pos.z + (progress + placedEntity.len + 2*s) * dirNormalized.z;
 				
-    			result.push({
-    				"template": wallSet.templates.tower,
-    				"pos": {"x": towerX, "z": towerZ},
-    				"angle": angle,
-    			});
+    				result.push({
+    					"template": wallSet.templates.tower,
+    					"pos": { "x": towerX, "z": towerZ },
+    					"angle": angle,
+    				});
 			}
 			
 			progress += placedEntity.len + 2*s;
@@ -160,15 +160,15 @@
 	// backtrack and try a wall segment of the next length instead. Note that we should prefer to use the long segments first since
 	// they can be replaced by gates.
 	
-	for each (var candSegment in candidateSegments)
+	for (let candSegment of candidateSegments)
 	{
 		segments.push(candSegment);
 		
-		var newDistSoFar = distSoFar + candSegment.len;
-		var r = d - newDistSoFar;
+		let newDistSoFar = distSoFar + candSegment.len;
+		let r = d - newDistSoFar;
 		
-		var rLowerBound = (1 - 2 * maxOverlap) * segments.length * t;
-		var rUpperBound = (1 - 2 * minOverlap) * segments.length * t;
+		let rLowerBound = (1 - 2 * maxOverlap) * segments.length * t;
+		let rUpperBound = (1 - 2 * minOverlap) * segments.length * t;
 		
 		if (r < rLowerBound)
 		{
@@ -179,7 +179,7 @@
 		}
 		else if (r > rUpperBound)
 		{
-			var recursiveResult = GetWallSegmentsRec(d, candidateSegments, minOverlap, maxOverlap, t, newDistSoFar, segments);
+			let recursiveResult = GetWallSegmentsRec(d, candidateSegments, minOverlap, maxOverlap, t, newDistSoFar, segments);
 			if (!recursiveResult)
 			{
 				// recursive search with this piece yielded no results, pop it and try the next one
@@ -192,7 +192,7 @@
 		else
 		{
 			// found a placement
-			return {"segments": segments, "r": r};
+			return { "segments": segments, "r": r };
 		}
 	}
 	
Index: binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml	(revision 18200)
+++ binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml	(working copy)
@@ -29,10 +29,11 @@
   <BuildRestrictions>
     <Territory>own neutral</Territory>
     <Category>CivilCentre</Category>
-    <Distance>
+    <Density>
       <FromClass>CivilCentre</FromClass>
-      <MinDistance>200</MinDistance>
-    </Distance>
+      <Distance>200</Distance>
+      <MaxEntity>0</MaxEntity>
+    </Density>
   </BuildRestrictions>
   <Capturable>
     <CapturePoints>2500</CapturePoints>
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml	(revision 18200)
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml	(working copy)
@@ -22,10 +22,11 @@
   </BuildingAI>
   <BuildRestrictions>
     <Category>DefenseTower</Category>
-    <Distance>
+    <Density>
       <FromClass>DefenseTower</FromClass>
-      <MinDistance>60</MinDistance>
-    </Distance>
+      <Distance>60</Distance>
+      <MaxEntity>0</MaxEntity>
+    </Density>
   </BuildRestrictions>
   <Cost>
     <BuildTime>150</BuildTime>
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml	(revision 18200)
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml	(working copy)
@@ -21,7 +21,12 @@
   </BuildingAI>
   <BuildRestrictions>
     <PlacementType>land-shore</PlacementType>
-    <Category>Wall</Category>
+    <Category>WallTower</Category>
+    <Density>
+      <FromClass>WallTower</FromClass>
+      <Distance>40</Distance>
+      <MaxEntity>2</MaxEntity>
+    </Density>
   </BuildRestrictions>
   <Capturable disable=""/>
   <Repairable>
@@ -52,7 +57,7 @@
   <Identity>
     <GenericName>Wall Turret</GenericName>
     <Tooltip>Shoots arrows. Garrison to defend a city wall against attackers.</Tooltip>
-    <Classes datatype="tokens">-ConquestCritical StoneWall Tower</Classes>
+    <Classes datatype="tokens">-ConquestCritical StoneWall Tower WallTower</Classes>
     <Icon>structures/tower.png</Icon>
     <RequiredTechnology>phase_town</RequiredTechnology>
   </Identity>
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_wooden_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_wooden_tower.xml	(revision 18200)
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_wooden_tower.xml	(working copy)
@@ -16,10 +16,11 @@
   </Attack>
   <BuildRestrictions>
     <Category>DefenseTower</Category>
-    <Distance>
+    <Density>
       <FromClass>DefenseTower</FromClass>
-      <MinDistance>40</MinDistance>
-    </Distance>
+      <Distance>40</Distance>
+      <MaxEntity>0</MaxEntity>
+    </Density>
   </BuildRestrictions>
   <Cost>
     <BuildTime>40</BuildTime>
Index: binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml	(revision 18200)
+++ binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml	(working copy)
@@ -26,10 +26,11 @@
   </BuildingAI>
   <BuildRestrictions>
     <Category>Fortress</Category>
-    <Distance>
+    <Density>
       <FromClass>Fortress</FromClass>
-      <MinDistance>80</MinDistance>
-    </Distance>
+      <Distance>80</Distance>
+      <MaxEntity>0</MaxEntity>
+    </Density>
   </BuildRestrictions>
   <Capturable>
     <CapturePoints>4000</CapturePoints>
