Index: binaries/data/mods/public/simulation/ai/petra/mapModule.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/mapModule.js	(revision 18021)
+++ binaries/data/mods/public/simulation/ai/petra/mapModule.js	(working copy)
@@ -3,6 +3,7 @@
 
 // other map functions
 m.TERRITORY_PLAYER_MASK = 0x1F;
+m.TERRITORY_BLINKING_MASK = 0x40;
 
 m.createObstructionMap = function(gameState, accessIndex, template)
 {
@@ -43,11 +44,28 @@
 	for (let k = 0; k < territoryMap.data.length; ++k)
 	{
 		let tilePlayer = (territoryMap.data[k] & m.TERRITORY_PLAYER_MASK);
-		if ((!buildNeutral && tilePlayer == 0) ||
-			(!buildOwn && tilePlayer == PlayerID) ||
-			(!buildAlly && tilePlayer != PlayerID && gameState.isPlayerAlly(tilePlayer)) ||
-			(!buildEnemy && tilePlayer != 0 && gameState.isPlayerEnemy(tilePlayer)))
-			continue;
+		let isConnected = (territoryMap.data[k] & m.TERRITORY_BLINKING_MASK) == 0;
+		if (tilePlayer == PlayerID)
+		{
+			if (!buildOwn || !buildNeutral && !isConnected)
+				continue;
+		}
+		else if (gameState.isPlayerMutualAlly(tilePlayer))
+		{
+			if (!buildAlly || !buildNeutral && !isConnected)
+				continue;
+		}
+		else if (tilePlayer == 0)
+		{
+			if (!buildNeutral)
+				continue;
+		}
+		else
+		{
+			if (!buildEnemy)
+				continue;
+		}
+
 		let x = ratio * (k % territoryMap.width);
 		let y = ratio * (Math.floor(k / territoryMap.width));
 		for (let ix = 0; ix < ratio; ++ix)
Index: binaries/data/mods/public/simulation/components/BuildRestrictions.js
===================================================================
--- binaries/data/mods/public/simulation/components/BuildRestrictions.js	(revision 18021)
+++ binaries/data/mods/public/simulation/components/BuildRestrictions.js	(working copy)
@@ -171,35 +171,50 @@
 
 	var pos = cmpPosition.GetPosition2D();
 	var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y);
-	var isOwn = (tileOwner == cmpPlayer.GetPlayerID());
-	var isNeutral = (tileOwner == 0);
-	var isAlly = !isOwn && cmpPlayer.IsAlly(tileOwner);
-	// We count neutral players as enemies, so you can't build in their territory.
-	var isEnemy = !isNeutral && (cmpPlayer.IsEnemy(tileOwner) || cmpPlayer.IsNeutral(tileOwner));
+	var isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y);
+	var isOwn = tileOwner == cmpPlayer.GetPlayerID();
+	var isMutualAlly = cmpPlayer.IsExclusiveMutualAlly(tileOwner);
+	var isNeutral = tileOwner == 0;
 
-	var territoryFail = true;
-	var territoryType = "";
-	if (isAlly && !this.HasTerritory("ally"))
-		// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
-		territoryType = markForTranslationWithContext("Territory type", "ally");
-	else if (isOwn && !this.HasTerritory("own"))
-		// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
-		territoryType = markForTranslationWithContext("Territory type", "own");
-	else if (isNeutral && !this.HasTerritory("neutral"))
-		// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
-		territoryType = markForTranslationWithContext("Territory type", "neutral");
-	else if (isEnemy && !this.HasTerritory("enemy"))
-		// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
-		territoryType = markForTranslationWithContext("Territory type", "enemy");
+	var invalidTerritory = "";
+	if (isOwn)
+	{
+		if (!this.HasTerritory("own"))
+			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
+			invalidTerritory = markForTranslationWithContext("Territory type", "own");
+		else if (!isConnected && !this.HasTerritory("neutral"))
+			// 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)
+	{
+		if (!this.HasTerritory("ally"))
+			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
+			invalidTerritory = markForTranslationWithContext("Territory type", "allied");
+		else if (!isConnected && !this.HasTerritory("neutral"))
+			// 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)
+	{
+		if (!this.HasTerritory("neutral"))
+			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
+			invalidTerritory = markForTranslationWithContext("Territory type", "neutral");
+	}
 	else
-		territoryFail = false;
+	{
+		// consider everything else enemy territory
+		if (!this.HasTerritory("enemy"))
+			// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.".
+			invalidTerritory = markForTranslationWithContext("Territory type", "enemy");
+	}
 
-	if (territoryFail)
+	if (invalidTerritory)
 	{
 		result.message = markForTranslation("%(name)s cannot be built in %(territoryType)s territory. Valid territories: %(validTerritories)s");
 		result.translateParameters.push("territoryType");
 		result.translateParameters.push("validTerritories");
-		result.parameters.territoryType = {"context": "Territory type", "message": territoryType};
+		result.parameters.territoryType = {"context": "Territory type", "message": invalidTerritory};
 		// gui code will join this array to a string
 		result.parameters.validTerritories = {"context": "Territory type list", "list": this.GetTerritories()};
 		return result;	// Fail
