Index: binaries/data/mods/public/gui/session/utility_functions.js
===================================================================
--- binaries/data/mods/public/gui/session/utility_functions.js	(révision 17846)
+++ binaries/data/mods/public/gui/session/utility_functions.js	(copie de travail)
@@ -72,10 +72,12 @@ function getRankIconSprite(entState)
 /**
  * Returns a message with the details of the trade gain.
  */
 function getTradingTooltip(gain)
 {
+	if (!gain)
+	return "";
 
 	var playerID = Engine.GetPlayerID();
 	var simState = GetSimState();
 	
 	var gainString = gain.traderGain;
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(révision 17846)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(copie de travail)
@@ -1665,17 +1665,17 @@ GuiInterface.prototype.GetTradingDetails
 		result = {
 			"type": "is first",
 			"hasBothMarkets": cmpEntityTrader.HasBothMarkets()
 		};
 		if (cmpEntityTrader.HasBothMarkets())
-			result.gain = cmpEntityTrader.GetGain();
+			result.gain = cmpEntityTrader.GetGoods().amount;
 	}
 	else if (data.target === secondMarket)
 	{
 		result = {
 			"type": "is second",
-			"gain": cmpEntityTrader.GetGain(),
+			"gain": cmpEntityTrader.GetGoods().amount,
 		};
 	}
 	else if (!firstMarket)
 	{
 		result = { "type": "set first" };
Index: binaries/data/mods/public/simulation/components/Trader.js
===================================================================
--- binaries/data/mods/public/simulation/components/Trader.js	(révision 17846)
+++ binaries/data/mods/public/simulation/components/Trader.js	(copie de travail)
@@ -19,23 +19,21 @@ Trader.prototype.Schema =
 		"<ref name='positiveDecimal'/>" +
 	"</element>";
 
 Trader.prototype.Init = function()
 {
-	this.firstMarket = INVALID_ENTITY;
-	this.secondMarket = INVALID_ENTITY;
-	// Gain from one pass between markets
-	this.gain = null;
+	this.markets = [];
+	this.index = -1;
 	// Selected resource for trading
 	this.requiredGoods = undefined;
 	// Currently carried goods
 	this.goods = { "type": null, "amount": null, "origin": null };
 };
 
-Trader.prototype.CalculateGain = function(firstMarket, secondMarket)
+Trader.prototype.CalculateGain = function(currentMarket, nextMarket)
 {
-	var gain = CalculateTraderGain(firstMarket, secondMarket, this.template, this.entity);
+	let gain = CalculateTraderGain(currentMarket, nextMarket, this.template, this.entity);
 	if (!gain)	// One of our markets must have been destroyed
 		return null;
 
 	// For ship increase gain for each garrisoned trader
 	// Calculate this here to save passing unnecessary stuff into the CalculateTraderGain function
@@ -65,15 +63,10 @@ Trader.prototype.CalculateGain = functio
 	}
 	
 	return gain;
 };
 
-Trader.prototype.GetGain = function()
-{
-	return this.gain;
-};
-
 // Set target as target market.
 // Return true if at least one of markets was changed.
 Trader.prototype.SetTargetMarket = function(target, source)
 {
 	// Check that target is a market
@@ -89,39 +82,37 @@ Trader.prototype.SetTargetMarket = funct
 		cmpTargetIdentity = Engine.QueryInterface(source, IID_Identity);
 		if (!cmpTargetIdentity)
 			return false;
 		if (!cmpTargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))
 			return false;
-
-		this.firstMarket = source;
-		this.secondMarket = INVALID_ENTITY;
+		this.markets = [source];
 	}
-
-	if (this.secondMarket)
+	if (this.markets.length >= 2)
 	{
 		// If we already have both markets - drop them
 		// and use the target as first market
-		this.firstMarket = target;
-		this.secondMarket = INVALID_ENTITY;
+		this.index = 0;
+		this.markets = [target];
 	}
-	else if (this.firstMarket)
+	else if (this.markets.length == 1)
 	{
 		// If we have only one market and target is different from it,
 		// set the target as second one
-		if (target == this.firstMarket)
+		if (target == this.markets[0])
 			marketsChanged = false;
 		else
-		{
-			this.secondMarket = target;
-			this.gain = this.CalculateGain(this.firstMarket, this.secondMarket);
+		{	this.index = 0;
+			this.markets.push(target);
+			this.goods.amount = this.CalculateGain(this.markets[0], this.markets[1]);
 		}
 	}
 	else
 	{
 		// Else we don't have target markets at all,
 		// set the target as first market
-		this.firstMarket = target;
+		this.index = 0;
+		this.markets = [target];
 	}
 	if (marketsChanged)
 	{
 		// Drop carried goods
 		this.goods.amount = null;
@@ -129,21 +120,21 @@ Trader.prototype.SetTargetMarket = funct
 	return marketsChanged;
 };
 
 Trader.prototype.GetFirstMarket = function()
 {
-	return this.firstMarket;
+	return this.markets[0] || null;
 };
 
 Trader.prototype.GetSecondMarket = function()
 {
-	return this.secondMarket;
+	return this.markets[1] || null;
 };
 
 Trader.prototype.HasBothMarkets = function()
 {
-	return this.firstMarket && this.secondMarket;
+	return this.markets.length >= 2;
 };
 
 Trader.prototype.GetRequiredGoods = function()
 {
 	return this.requiredGoods;
@@ -184,10 +175,19 @@ Trader.prototype.CanTrade = function(tar
 	return true;
 };
 
 Trader.prototype.PerformTrade = function(currentMarket)
 {
+	let previousMarket = this.markets[(this.index+this.markets.length) % this.markets.length];
+
+	this.index = ++this.index % this.markets.length;
+
+	let nextMarket = this.markets[(this.index+this.markets.length) % this.markets.length];
+
+	if (previousMarket != currentMarket)
+		warn("Markets are not matching.");
+
 	if (this.goods.amount && this.goods.amount.traderGain)
 	{
 		var cmpPlayer = QueryOwnerInterface(this.entity);
 		if (cmpPlayer)
 			cmpPlayer.AddResource(this.goods.type, this.goods.amount.traderGain);
@@ -196,26 +196,26 @@ Trader.prototype.PerformTrade = function
 		if (cmpStatisticsTracker)
 			cmpStatisticsTracker.IncreaseTradeIncomeCounter(this.goods.amount.traderGain);
 
 		if (this.goods.amount.market1Gain)
 		{
-			var cmpPlayer = QueryOwnerInterface(this.firstMarket);
+			let cmpPlayer = QueryOwnerInterface(previousMarket);
 			if (cmpPlayer)
 				cmpPlayer.AddResource(this.goods.type, this.goods.amount.market1Gain);
 
-			var cmpStatisticsTracker = QueryOwnerInterface(this.firstMarket, IID_StatisticsTracker);
+			let cmpStatisticsTracker = QueryOwnerInterface(previousMarket, IID_StatisticsTracker);
 			if (cmpStatisticsTracker)
 				cmpStatisticsTracker.IncreaseTradeIncomeCounter(this.goods.amount.market1Gain);
 		}
 
 		if (this.goods.amount.market2Gain)
 		{
-			var cmpPlayer = QueryOwnerInterface(this.secondMarket);
+			let cmpPlayer = QueryOwnerInterface(currentMarket);
 			if (cmpPlayer)
 				cmpPlayer.AddResource(this.goods.type, this.goods.amount.market2Gain);
 
-			var cmpStatisticsTracker = QueryOwnerInterface(this.secondMarket, IID_StatisticsTracker);
+			let cmpStatisticsTracker = QueryOwnerInterface(currentMarket, IID_StatisticsTracker);
 			if (cmpStatisticsTracker)
 				cmpStatisticsTracker.IncreaseTradeIncomeCounter(this.goods.amount.market2Gain);
 		}
 	}
 
@@ -232,36 +232,27 @@ Trader.prototype.PerformTrade = function
 
 		if (!nextGoods || RESOURCES.indexOf(nextGoods) == -1)
 			nextGoods = "metal";
 	}
 	this.goods.type = nextGoods;
-	this.goods.amount = this.CalculateGain(this.firstMarket, this.secondMarket);
+	this.goods.amount = this.CalculateGain(currentMarket, nextMarket);
 	this.goods.origin = currentMarket;
 };
 
 Trader.prototype.GetGoods = function()
 {
 	return this.goods;
 };
 
-Trader.prototype.GetNextMarket = function()
-{
-	if (this.goods.amount && this.goods.origin == this.firstMarket)
-		return this.secondMarket;
-
-	if (this.goods.amount && this.goods.origin != this.secondMarket)
-		this.goods.amount = null;   // leftover from previous trading
-	return this.firstMarket;
-};
-
 Trader.prototype.StopTrading = function()
 {
+	this.index = -1;
+	this.markets = [];
 	// Drop carried goods
 	this.goods.amount = null;
 	// Reset markets
-	this.firstMarket = INVALID_ENTITY;
-	this.secondMarket = INVALID_ENTITY;
+	this.markets = [];
 };
 
 // Get range in which deals with market are available,
 // i.e. trader should be in no more than MaxDistance from market
 // to be able to trade with it.
@@ -275,9 +266,9 @@ Trader.prototype.GetRange = function()
 };
 
 Trader.prototype.OnGarrisonedUnitsChanged = function()
 {
 	if (this.HasBothMarkets())
-		this.gain = this.CalculateGain(this.firstMarket, this.secondMarket);
+		this.goods.amount = this.CalculateGain(this.markets[0], this.markets[1]);
 };
 
 Engine.RegisterComponentType(IID_Trader, "Trader", Trader);
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js	(révision 17846)
+++ binaries/data/mods/public/simulation/components/UnitAI.js	(copie de travail)
@@ -652,21 +652,15 @@ UnitAI.prototype.UnitFsmSpec = {
 		{
 			this.FinishOrder();
 			return;
 		}
 
-		var nextMarket = cmpTrader.GetNextMarket();
-		if (nextMarket == this.order.data.firstMarket)
-			var state = "TRADE.APPROACHINGFIRSTMARKET";
-		else
-			var state = "TRADE.APPROACHINGSECONDMARKET";
-
 		// TODO find the nearest way-point from our position, and start with it
 		this.waypoints = undefined;
-		if (this.MoveToMarket(nextMarket))
+		if (this.MoveToMarket(this.order.data.target))
 			// We've started walking to the next market
-			this.SetNextState(state);
+			this.SetNextState("TRADE.APPROACHINGMARKET");
 		else
 			this.FinishOrder();
 	},
 
 	"Order.Repair": function(msg) {
@@ -2603,39 +2597,23 @@ UnitAI.prototype.UnitFsmSpec = {
 			"Attacked": function(msg) {
 				// Ignore attack
 				// TODO: Inform player
 			},
 
-			"APPROACHINGFIRSTMARKET": {
-				"enter": function () {
-					this.SelectAnimation("move");
-				},
-
-				"MoveCompleted": function() {
-					if (this.waypoints && this.waypoints.length)
-					{
-						if (!this.MoveToMarket(this.order.data.firstMarket))
-							this.StopTrading();
-					}
-					else
-						this.PerformTradeAndMoveToNextMarket(this.order.data.firstMarket, this.order.data.secondMarket, "APPROACHINGSECONDMARKET");
-				},
-			},
-
-			"APPROACHINGSECONDMARKET": {
+			"APPROACHINGMARKET": {
 				"enter": function () {
 					this.SelectAnimation("move");
 				},
 
 				"MoveCompleted": function() {
 					if (this.waypoints && this.waypoints.length)
 					{
-						if (!this.MoveToMarket(this.order.data.secondMarket))
+						if (!this.MoveToMarket(this.order.data.target))
 							this.StopTrading();
 					}
 					else
-						this.PerformTradeAndMoveToNextMarket(this.order.data.secondMarket, this.order.data.firstMarket, "APPROACHINGFIRSTMARKET");
+						this.PerformTradeAndMoveToNextMarket(this.order.data.target);
 				},
 			},
 		},
 
 		"REPAIR": {
@@ -5168,11 +5146,11 @@ UnitAI.prototype.SetupTradeRoute = funct
 		return;
 
 	var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader);
 	if (cmpTrader.HasBothMarkets())
 	{
-		var data = { "firstMarket": cmpTrader.GetFirstMarket(), "secondMarket": cmpTrader.GetSecondMarket(), "route": route, "force": false };
+		let data = { "target": cmpTrader.GetFirstMarket(), "firstMarket": cmpTrader.GetFirstMarket(), "secondMarket": cmpTrader.GetSecondMarket(), "route": route, "force": false };
 
 		if (this.expectedRoute)
 		{
 			if (!route && this.expectedRoute.length)
 				data.route = this.expectedRoute.slice();
@@ -5228,46 +5206,47 @@ UnitAI.prototype.MoveToMarket = function
 	}
 
 	return ok;
 };
 
-UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket, nextMarket, nextFsmStateName)
+UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket)
 {
 	if (!this.CanTrade(currentMarket))
 	{
 		this.StopTrading();
 		return;
 	}
 
-	if (this.CheckTargetRange(currentMarket, IID_Trader))
+	if (!this.CheckTargetRange(currentMarket, IID_Trader))
 	{
-		var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader);
-		cmpTrader.PerformTrade(currentMarket);
-		if (!cmpTrader.GetGain().traderGain)
-		{
+		if (!this.MoveToMarket(currentMarket))	// If the current market is not reached try again
 			this.StopTrading();
-			return;
-		}
-
-		if (this.order.data.route && this.order.data.route.length)
-		{
-			this.waypoints = this.order.data.route.slice();
-			if (nextFsmStateName == "APPROACHINGSECONDMARKET")
-				this.waypoints.reverse();
-			this.waypoints.unshift(null);  // additionnal dummy point for the market
-		}
+		return;
+	}
 
-		if (this.MoveToMarket(nextMarket))	// We've started walking to the next market
-			this.SetNextState(nextFsmStateName);
-		else
-			this.StopTrading();
+	let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader);
+	cmpTrader.PerformTrade(currentMarket);
+	let nextMarket = cmpTrader.markets[cmpTrader.index];
+	if (!cmpTrader.GetGoods().amount.traderGain)
+	{
+		this.StopTrading();
+		return;
 	}
-	else
+
+	if (this.order.data.route && this.order.data.route.length)
 	{
-		if (!this.MoveToMarket(currentMarket))	// If the current market is not reached try again
-			this.StopTrading();
+		this.waypoints = this.order.data.route.slice();
+		if (this.order.data.target == cmpTrader.GetSecondMarket())
+			this.waypoints.reverse();
+		this.waypoints.unshift(null);  // additionnal dummy point for the market
 	}
+
+	this.order.data.target = nextMarket;
+	if (this.MoveToMarket(nextMarket))	// We've started walking to the next market
+		this.SetNextState("APPROACHINGMARKET");
+	else
+		this.StopTrading();
 };
 
 UnitAI.prototype.StopTrading = function()
 {
 	this.StopMoving();
