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 +