Index: binaries/data/mods/public/gui/session/unit_actions.js
===================================================================
--- binaries/data/mods/public/gui/session/unit_actions.js	(révision 19083)
+++ binaries/data/mods/public/gui/session/unit_actions.js	(copie de travail)
@@ -133,14 +133,14 @@ var unitActions =
 		"getActionInfo": function(entState, targetState)
 		{
 			if (!entState.attack || !targetState.hitpoints)
 				return false;
 
-			return {
-				"possible": Engine.GuiInterfaceCall("CanCapture", {
+			return { "possible": Engine.GuiInterfaceCall("CanAttack", {
 					"entity": entState.id,
-					"target": targetState.id
+					"target": targetState.id,
+					"types": ["Capture"]
 				})
 			};
 		},
 		"actionCheck": function(target)
 		{
@@ -181,11 +181,12 @@ var unitActions =
 				return false;
 
 			return {
 				"possible": Engine.GuiInterfaceCall("CanAttack", {
 					"entity": entState.id,
-					"target": targetState.id
+					"target": targetState.id,
+					"types": ["Ranged", "Melee"]
 				})
 			};
 		},
 		"hotkeyActionCheck": function(target)
 		{
@@ -438,11 +439,11 @@ var unitActions =
 				"entity": selection[0]
 			});
 
 			return true;
 		},
-		"getActionInfo":  function(entState, targetState)
+		"getActionInfo": function(entState, targetState)
 		{
 			if (!targetState.resourceSupply)
 				return false;
 
 			let resource = findGatherType(entState, targetState.resourceSupply);
Index: binaries/data/mods/public/simulation/components/Attack.js
===================================================================
--- binaries/data/mods/public/simulation/components/Attack.js	(révision 19083)
+++ binaries/data/mods/public/simulation/components/Attack.js	(copie de travail)
@@ -206,35 +206,48 @@ Attack.prototype.GetRestrictedClasses =
 		return this.template[type].RestrictedClasses._string.split(/\s+/);
 
 	return [];
 };
 
-Attack.prototype.CanAttack = function(target)
+Attack.prototype.CanAttack = function(target, wantedTypes)
 {
 	let cmpFormation = Engine.QueryInterface(target, IID_Formation);
 	if (cmpFormation)
 		return true;
 
 	let cmpThisPosition = Engine.QueryInterface(this.entity, IID_Position);
 	let cmpTargetPosition = Engine.QueryInterface(target, IID_Position);
 	if (!cmpThisPosition || !cmpTargetPosition || !cmpThisPosition.IsInWorld() || !cmpTargetPosition.IsInWorld())
 		return false;
 
-	// Check if the relative height difference is larger than the attack range
-	// If the relative height is bigger, it means they will never be able to
-	// reach each other, no matter how close they come.
-	let heightDiff = Math.abs(cmpThisPosition.GetHeightOffset() - cmpTargetPosition.GetHeightOffset());
-
 	const cmpIdentity = Engine.QueryInterface(target, IID_Identity);
 	if (!cmpIdentity)
 		return undefined;
 
+	let cmpEntityPlayer = QueryOwnerInterface(this.entity);
+	let cmpTargetPlayer = QueryOwnerInterface(target);
+	if (!cmpTargetPlayer || !cmpEntityPlayer)
+		return false;
+
+	let targetOwner = cmpEntityPlayer.GetPlayerID();
 	const targetClasses = cmpIdentity.GetClassesList();
+	let cmpCapturable = QueryMiragedInterface(target, IID_Capturable);
+	if (targetClasses.indexOf("Domestic") == -1 && !cmpEntityPlayer.IsEnemy(cmpTargetPlayer.GetPlayerID()) &&
+	   (!cmpCapturable || !cmpCapturable.CanCapture(targetOwner)))
+		return false;
+
+	// Check if the relative height difference is larger than the attack range
+	// If the relative height is bigger, it means they will never be able to
+	// reach each other, no matter how close they come.
+	let heightDiff = Math.abs(cmpThisPosition.GetHeightOffset() - cmpTargetPosition.GetHeightOffset());
 
 	for (let type of this.GetAttackTypes())
 	{
-		if (type == "Capture" && !QueryMiragedInterface(target, IID_Capturable))
+		if (wantedTypes && (wantedTypes.indexOf(type) == -1 || wantedTypes.indexOf("no" + type) != -1))
+			continue;
+
+		if (type == "Capture" && (!cmpCapturable || !cmpCapturable.CanCapture(targetOwner)))
 			continue;
 
 		if (heightDiff > this.GetRange(type).max)
 			continue;
 
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(révision 19083)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(copie de travail)
@@ -1828,41 +1828,14 @@ GuiInterface.prototype.GetTradingDetails
 		result = { "type": "set first" };
 	}
 	return result;
 };
 
-GuiInterface.prototype.CanCapture = function(player, data)
-{
-	let cmpAttack = Engine.QueryInterface(data.entity, IID_Attack);
-	if (!cmpAttack)
-		return false;
-
-	let owner = QueryOwnerInterface(data.entity).GetPlayerID();
-
-	let cmpCapturable = QueryMiragedInterface(data.target, IID_Capturable);
-	if (cmpCapturable && cmpCapturable.CanCapture(owner) && cmpAttack.GetAttackTypes().indexOf("Capture") != -1)
-		return cmpAttack.CanAttack(data.target);
-
-	return false;
-};
-
 GuiInterface.prototype.CanAttack = function(player, data)
 {
 	let cmpAttack = Engine.QueryInterface(data.entity, IID_Attack);
-	if (!cmpAttack)
-		return false;
-
-	let cmpEntityPlayer = QueryOwnerInterface(data.entity, IID_Player);
-	let cmpTargetPlayer = QueryOwnerInterface(data.target, IID_Player);
-	if (!cmpEntityPlayer || !cmpTargetPlayer)
-		return false;
-
-	// if the owner is an enemy, it's up to the attack component to decide
-	if (cmpEntityPlayer.IsEnemy(cmpTargetPlayer.GetPlayerID()))
-		return cmpAttack.CanAttack(data.target);
-
-	return false;
+	return cmpAttack && cmpAttack.CanAttack(data.target, data.types || undefined);
 };
 
 /*
  * Returns batch build time.
  */
@@ -2003,11 +1976,10 @@ let exposedFunctions = {
 	"PlaySound": 1,
 	"FindIdleUnits": 1,
 	"HasIdleUnits": 1,
 	"GetTradingRouteGain": 1,
 	"GetTradingDetails": 1,
-	"CanCapture": 1,
 	"CanAttack": 1,
 	"GetBatchTime": 1,
 
 	"IsMapRevealed": 1,
 	"SetPathfinderDebugOverlay": 1,
Index: binaries/data/mods/public/simulation/components/tests/test_Attack.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Attack.js	(révision 19083)
+++ binaries/data/mods/public/simulation/components/tests/test_Attack.js	(copie de travail)
@@ -20,11 +20,12 @@ function attackComponentTest(defenderCla
 		AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
 			"GetPlayerByID": () => playerEnt1
 		});
 
 		AddMock(playerEnt1, IID_Player, {
-			"GetPlayerID": () => 1
+			"GetPlayerID": () => 1,
+			"IsEnemy": () => true
 		});
 	}
 
 	let attacker = entityID;
 
@@ -90,10 +91,14 @@ function attackComponentTest(defenderCla
 	AddMock(defender, IID_Position, {
 		"IsInWorld": () => true,
 		"GetHeightOffset": () => 0
 	});
 
+	AddMock(defender, IID_Ownership, {
+		"GetOwner": () => 1
+	});
+
 	test_function(attacker, cmpAttack, defender);
 }
 
 // Validate template getter functions
 attackComponentTest(undefined, (attacker, cmpAttack, defender) => {
