diff --git a/binaries/data/mods/public/gui/session/unit_actions.js b/binaries/data/mods/public/gui/session/unit_actions.js
index 11816a5cf6..0053b7820b 100644
--- a/binaries/data/mods/public/gui/session/unit_actions.js
+++ b/binaries/data/mods/public/gui/session/unit_actions.js
@@ -307,11 +307,12 @@ var unitActions =
},
"getActionInfo": function(entState, targetState)
{
- if (targetState.foundation || !entState.trader)
+ if (targetState.foundation || !entState.trader || !targetState.market)
return false;
if (!playerCheck(entState, targetState, ["Player", "Ally"]))
return false;
- if (!(hasClass(entState, "Organic") && hasClass(targetState, "Market")) && !(hasClass(entState, "Ship") && hasClass(targetState, "NavalMarket")))
+ if (!(targetState.market.land && hasClass(entState, "Organic") ||
+ targetState.market.naval && hasClass(entState, "Ship")))
return false;
var tradingData = {"trader": entState.id, "target": targetState.id};
@@ -529,8 +530,8 @@ var unitActions =
data.resourceType = resourceType;
data.resourceTemplate = targetState.template;
}
- else if (hasClass(entState, "Market") && hasClass(targetState, "Market") && entState.id != targetState.id &&
- (!hasClass(entState, "NavalMarket") || hasClass(targetState, "NavalMarket")) && !playerCheck(entState, targetState, ["Enemy"]))
+ else if (entState.market && targetState.market && entState.id != targetState.id &&
+ (!entState.market.naval || targetState.market.naval) && !playerCheck(entState, targetState, ["Enemy"]))
{
// Find a trader (if any) that this building can produce.
var trader;
@@ -881,7 +882,7 @@ var g_EntityCommands =
"select-trading-goods": {
"getInfo": function(entState)
{
- if (!hasClass(entState, "Market"))
+ if (!entState.market)
return false;
return {
"tooltip": translate("Select trading goods"),
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
index 0ceac7e66b..97e77a7593 100644
--- a/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -234,6 +234,7 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
"garrisonHolder": null,
"gate": null,
"guard": null,
+ "market": null,
"mirage": null,
"pack": null,
"player": -1,
@@ -288,6 +289,13 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
if (cmpBuilder)
ret.builder = true;
+ let cmpMarket = Engine.QueryInterface(ent, IID_Market);
+ if (cmpMarket)
+ ret.market = {
+ "land": cmpMarket.HasType("land"),
+ "naval": cmpMarket.HasType("naval"),
+ };
+
let cmpPack = Engine.QueryInterface(ent, IID_Pack);
if (cmpPack)
ret.pack = {
diff --git a/binaries/data/mods/public/simulation/components/Market.js b/binaries/data/mods/public/simulation/components/Market.js
new file mode 100644
index 0000000000..09356bb5b2
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/Market.js
@@ -0,0 +1,71 @@
+function Market() {}
+
+Market.prototype.Schema =
+ "" +
+ "" +
+ "" +
+ "" +
+ "land" +
+ "naval" +
+ "" +
+ "" +
+ "
" +
+ "";
+
+Market.prototype.Init = function()
+{
+ this.traders = new Set(); // list of traders with a route on this market
+ this.tradeType = new Set(this.template.TradeType.split(/\s+/));
+};
+
+Market.prototype.AddTrader = function(ent)
+{
+ this.traders.add(ent);
+};
+
+Market.prototype.RemoveTrader = function(ent)
+{
+ this.traders.delete(ent);
+};
+
+Market.prototype.HasType = function(type)
+{
+ return this.tradeType.has(type);
+};
+
+/**
+ * Check if all traders with a route on this market can still trade
+ */
+Market.prototype.OnDiplomacyChanged = function(msg)
+{
+ for (let ent of this.traders)
+ {
+ let cmpTrader = Engine.QueryInterface(ent, IID_Trader);
+ if (!cmpTrader)
+ this.RemoveTrader(ent);
+ else if (!cmpTrader.CanTrade(this.entity))
+ {
+ this.RemoveTrader(ent);
+ cmpTrader.RemoveMarket(this.entity);
+ }
+ }
+};
+
+Market.prototype.OnOwnershipChanged = function(msg)
+{
+ for (let ent of this.traders)
+ {
+ let cmpTrader = Engine.QueryInterface(ent, IID_Trader);
+ if (!cmpTrader)
+ this.RemoveTrader(ent);
+ else if (msg.to == -1)
+ cmpTrader.RemoveMarket(this.entity);
+ else if (!cmpTrader.CanTrade(this.entity))
+ {
+ this.RemoveTrader(ent);
+ cmpTrader.RemoveMarket(this.entity);
+ }
+ }
+};
+
+Engine.RegisterComponentType(IID_Market, "Market", Market);
diff --git a/binaries/data/mods/public/simulation/components/Trader.js b/binaries/data/mods/public/simulation/components/Trader.js
index 516403f40a..67aaa394ca 100644
--- a/binaries/data/mods/public/simulation/components/Trader.js
+++ b/binaries/data/mods/public/simulation/components/Trader.js
@@ -1,5 +1,5 @@
-// See helpers/TraderGain.js for the CalculateTaderGain() function which works out how many
-// resources a trader gets
+// See helpers/TraderGain.js for the CalculateTaderGain() function which works out how many
+// resources a trader gets
// Additional gain for ships for each garrisoned trader, in percents
const GARRISONED_TRADER_ADDITION = 20;
@@ -61,7 +61,7 @@ Trader.prototype.CalculateGain = function(currentMarket, nextMarket)
gain.market2Gain = Math.round(garrisonMultiplier * gain.market2Gain);
}
}
-
+
return gain;
};
@@ -69,29 +69,32 @@ Trader.prototype.CalculateGain = function(currentMarket, nextMarket)
// Return true if at least one of markets was changed.
Trader.prototype.SetTargetMarket = function(target, source)
{
- // Check that target is a market
- var cmpTargetIdentity = Engine.QueryInterface(target, IID_Identity);
- if (!cmpTargetIdentity)
- return false;
- if (!cmpTargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))
+ var cmpTargetMarket = Engine.QueryInterface(target, IID_Market);
+ if (!cmpTargetMarket)
return false;
if (source)
{
// Establish a trade route with both markets in one go.
- cmpTargetIdentity = Engine.QueryInterface(source, IID_Identity);
- if (!cmpTargetIdentity)
- return false;
- if (!cmpTargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))
+ let cmpSourceMarket = Engine.QueryInterface(source, IID_Market);
+ if (!cmpSourceMarket)
return false;
this.markets = [source];
+ cmpSourceMarket.AddTrader(this.entity);
}
if (this.markets.length >= 2)
{
// If we already have both markets - drop them
// and use the target as first market
+ for (let market of this.markets)
+ {
+ let cmpMarket = Engine.QueryInterface(market, IID_Market);
+ if (cmpMarket)
+ cmpMarket.RemoveTrader(this.entity);
+ }
this.index = 0;
this.markets = [target];
+ cmpTargetMarket.AddTrader(this.entity);
}
else if (this.markets.length == 1)
{
@@ -103,6 +106,7 @@ Trader.prototype.SetTargetMarket = function(target, source)
{
this.index = 0;
this.markets.push(target);
+ cmpTargetMarket.AddTrader(this.entity);
this.goods.amount = this.CalculateGain(this.markets[0], this.markets[1]);
}
}
@@ -112,6 +116,7 @@ Trader.prototype.SetTargetMarket = function(target, source)
// set the target as first market
this.index = 0;
this.markets = [target];
+ cmpTargetMarket.AddTrader(this.entity);
}
// Drop carried goods if markets were changed
this.goods.amount = null;
@@ -150,16 +155,16 @@ Trader.prototype.SetRequiredGoods = function(requiredGoods)
Trader.prototype.CanTrade = function(target)
{
var cmpTraderIdentity = Engine.QueryInterface(this.entity, IID_Identity);
- var cmpTargetIdentity = Engine.QueryInterface(target, IID_Identity);
// Check that the target exists
- if (!cmpTargetIdentity)
+ var cmpTargetMarket = Engine.QueryInterface(target, IID_Market);
+ if (!cmpTargetMarket)
return false;
// Check that the target is not a foundation
var cmpTargetFoundation = Engine.QueryInterface(target, IID_Foundation);
if (cmpTargetFoundation)
return false;
- var landTradingPossible = cmpTraderIdentity.HasClass("Organic") && cmpTargetIdentity.HasClass("Market");
- var seaTradingPossible = cmpTraderIdentity.HasClass("Ship") && cmpTargetIdentity.HasClass("NavalMarket");
+ var landTradingPossible = cmpTraderIdentity.HasClass("Organic") && cmpTargetMarket.HasType("land");
+ var seaTradingPossible = cmpTraderIdentity.HasClass("Ship") && cmpTargetMarket.HasType("naval");
if (!landTradingPossible && !seaTradingPossible)
return false;
@@ -242,8 +247,24 @@ Trader.prototype.GetGoods = function()
return this.goods;
};
+/**
+ * Called when this trader can no longer trade with the market
+ */
+Trader.prototype.RemoveMarket = function(market)
+{
+ let index = this.markets.indexOf(market);
+ if (index != -1)
+ this.markets.splice(index, 1);
+};
+
Trader.prototype.StopTrading = function()
{
+ for (let market of this.markets)
+ {
+ let cmpMarket = Engine.QueryInterface(market, IID_Market);
+ if (cmpMarket)
+ cmpMarket.RemoveTrader(this.entity);
+ }
this.index = -1;
this.markets = [];
// Drop carried goods
diff --git a/binaries/data/mods/public/simulation/components/interfaces/Market.js b/binaries/data/mods/public/simulation/components/interfaces/Market.js
new file mode 100644
index 0000000000..78ad711129
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/interfaces/Market.js
@@ -0,0 +1 @@
+Engine.RegisterInterface("Market");
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml b/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
index 99f12c8bb4..5373825be9 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
@@ -32,6 +32,9 @@
25
25
+
+ land
+
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml b/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
index 0ea502c992..a27c0847ed 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
@@ -34,6 +34,9 @@
0
0
+
+ land naval
+