Ticket #4366: 4366_barterUI_v1-5.patch

File 4366_barterUI_v1-5.patch, 28.7 KB (added by s0600204, 3 years ago)

Updated patch

  • binaries/data/config/default.cfg

    diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg
    index 47f8528cf..b31e6467e 100644
    a b console.toggle = BackQuote, F9 ; Open/close console 
    157157fps.toggle = "Alt+F"                  ; Toggle frame counter
    158158realtime.toggle = "Alt+T"             ; Toggle current display of computer time
    159159session.devcommands.toggle = "Alt+D"  ; Toggle developer commands panel
    160 session.gui.toggle = "Alt+G"          ; Toggle visibility of session GUI
    161 menu.toggle = "F10"                   ; Toggle in-game menu
    162160timeelapsedcounter.toggle = "F12"     ; Toggle time elapsed counter
    163161session.showstatusbars = Tab          ; Toggle display of status bars
    164162session.highlightguarding = PgDn      ; Toggle highlight of guarding units
    deselectgroup = Ctrl ; Modifier to deselect units when clicking group ic 
    294292rotate.cw = RightBracket     ; Rotate building placement preview clockwise
    295293rotate.ccw = LeftBracket     ; Rotate building placement preview anticlockwise
    296294
     295[hotkey.session.gui]
     296toggle = "Alt+G"             ; Toggle visibility of session GUI
     297menu.toggle = "F10"          ; Toggle in-game menu
     298barter.toggle = "Ctrl+B"     ; Toggle in-game barter/trade page
     299
    297300[hotkey.session.savedgames]
    298301delete = Delete               ; Delete the selected saved game asking confirmation
    299302noconfirmation = Shift        ; Do not ask confirmation when deleting a game
  • binaries/data/mods/public/gui/session/hotkeys/misc.xml

    diff --git a/binaries/data/mods/public/gui/session/hotkeys/misc.xml b/binaries/data/mods/public/gui/session/hotkeys/misc.xml
    index 87844d24c..b9a40bea1 100644
    a b  
    1212        <action on="Press">openChat(true);</action>
    1313    </object>
    1414
    15     <object hotkey="menu.toggle">
     15    <object hotkey="session.gui.menu.toggle">
    1616        <action on="Press">toggleMenu();</action>
    1717    </object>
    1818
     19    <object hotkey="session.gui.barter.toggle">
     20        <action on="Press">toggleTrade();</action>
     21    </object>
     22
    1923    <object hotkey="silhouettes">
    2024        <action on="Press">
    2125            var newSetting = !Engine.Renderer_GetSilhouettesEnabled();
     
    6872    </object>
    6973
    7074    <object hotkey="session.massbarter">
    71         <action on="Press">updateSelectionDetails();</action>
    72         <action on="Release">updateSelectionDetails();</action>
     75        <action on="Press">
     76            updateSelectionDetails();
     77            updateBarterButtons();
     78        </action>
     79        <action on="Release">
     80            updateSelectionDetails();
     81            updateBarterButtons();
     82        </action>
    7383    </object>
    7484
    7585    <!-- Find idle warrior - TODO: Potentially move this to own UI button? -->
  • binaries/data/mods/public/gui/session/menu.js

    diff --git a/binaries/data/mods/public/gui/session/menu.js b/binaries/data/mods/public/gui/session/menu.js
    index 12f2a025e..9a7cf7e9b 100644
    a b const STEP = 5; 
    2828// Shown in the trade dialog.
    2929const g_IdleTraderTextColor = "orange";
    3030
     31const BARTER_RESOURCE_AMOUNT_TO_SELL = 100;
     32const BARTER_BUNCH_MULTIPLIER = 5;
     33const BARTER_ACTIONS = ["Buy", "Sell"];
     34var g_BarterSell;
     35
    3136var g_IsMenuOpen = false;
    3237
    3338var g_IsDiplomacyOpen = false;
    function openTrade() 
    489494
    490495    g_IsTradeOpen = true;
    491496
    492     var updateButtons = function()
     497    let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer);
     498    let button = {};
     499    let resCodes = g_ResourceData.GetCodes();
     500    let currTradeSelection = resCodes[0];
     501
     502    let updateTradeButtons = function()
    493503    {
    494504        for (let res in button)
    495505        {
    496506            button[res].label.caption = proba[res] + "%";
    497507
    498             button[res].sel.hidden = !controlsPlayer(g_ViewedPlayer) || res != selec;
    499             button[res].up.hidden = !controlsPlayer(g_ViewedPlayer) || res == selec || proba[res] == 100 || proba[selec] == 0;
    500             button[res].dn.hidden = !controlsPlayer(g_ViewedPlayer) || res == selec || proba[res] == 0 || proba[selec] == 100;
     508            button[res].sel.hidden = !controlsPlayer(g_ViewedPlayer) || res != currTradeSelection;
     509            button[res].up.hidden = !controlsPlayer(g_ViewedPlayer) || res == currTradeSelection || proba[res] == 100 || proba[currTradeSelection] == 0;
     510            button[res].dn.hidden = !controlsPlayer(g_ViewedPlayer) || res == currTradeSelection || proba[res] == 0 || proba[currTradeSelection] == 100;
    501511        }
    502512    };
    503513
    504     let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer);
    505     let button = {};
    506     let resCodes = g_ResourceData.GetCodes();
    507     let selec = resCodes[0];
    508514    hideRemaining("tradeResources", resCodes.length);
    509515    Engine.GetGUIObjectByName("tradeHelp").hidden = false;
    510516
    511517    for (let i = 0; i < resCodes.length; ++i)
    512518    {
     519        let resCode = resCodes[i];
     520
     521        // Barter
     522        barterOpenCommon(resCode, i, "barter", updateBarterButtons);
     523        setPanelObjectPosition(Engine.GetGUIObjectByName("barterResource[" + i + "]"), i, i+1);
     524
     525        // Trade
    513526        let tradeResource = Engine.GetGUIObjectByName("tradeResource["+i+"]");
    514527        if (!tradeResource)
    515528        {
    function openTrade() 
    519532
    520533        setPanelObjectPosition(tradeResource, i, i+1);
    521534
    522         let resCode = resCodes[i];
    523         proba[resCode] = proba[resCode] || 0;
    524 
    525535        let icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]");
    526536        icon.sprite = "stretched:session/icons/resources/" + resCode + ".png";
    527537
    function openTrade() 
    535545            "sel": Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]")
    536546        };
    537547
     548        proba[resCode] = proba[resCode] || 0;
     549
    538550        let buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]");
    539551        buttonResource.enabled = controlsPlayer(g_ViewedPlayer);
    540         buttonResource.onpress = (function(resource){
     552        buttonResource.onPress = (function(resource){
    541553            return function() {
    542554                if (Engine.HotkeyIsPressed("session.fulltradeswap"))
    543555                {
    function openTrade() 
    546558                    proba[resource] = 100;
    547559                    Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba});
    548560                }
    549                 selec = resource;
    550                 updateButtons();
     561                currTradeSelection = resource;
     562                updateTradeButtons();
    551563            };
    552564        })(resCode);
    553565
    554566        buttonUp.enabled = controlsPlayer(g_ViewedPlayer);
    555         buttonUp.onpress = (function(resource){
     567        buttonUp.onPress = (function(resource){
    556568            return function() {
    557                 proba[resource] += Math.min(STEP, proba[selec]);
    558                 proba[selec]    -= Math.min(STEP, proba[selec]);
     569                proba[resource] += Math.min(STEP, proba[currTradeSelection]);
     570                proba[currTradeSelection] -= Math.min(STEP, proba[currTradeSelection]);
    559571                Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba});
    560                 updateButtons();
     572                updateTradeButtons();
    561573            };
    562574        })(resCode);
    563575
    564576        buttonDn.enabled = controlsPlayer(g_ViewedPlayer);
    565         buttonDn.onpress = (function(resource){
     577        buttonDn.onPress = (function(resource){
    566578            return function() {
    567                 proba[selec]    += Math.min(STEP, proba[resource]);
     579                proba[currTradeSelection] += Math.min(STEP, proba[resource]);
    568580                proba[resource] -= Math.min(STEP, proba[resource]);
    569581                Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba});
    570                 updateButtons();
     582                updateTradeButtons();
    571583            };
    572584        })(resCode);
    573585    }
    574     updateButtons();
     586    updateTradeButtons();
    575587
    576588    let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer);
    577     Engine.GetGUIObjectByName("landTraders").caption = getIdleLandTradersText(traderNumber);
    578     Engine.GetGUIObjectByName("shipTraders").caption = getIdleShipTradersText(traderNumber);
     589    Engine.GetGUIObjectByName("traders").caption = getIdleLandTradersText(traderNumber) + "\n\n" + getIdleShipTradersText(traderNumber);
    579590    Engine.GetGUIObjectByName("tradeDialogPanel").hidden = false;
    580591}
    581592
     593function updateBarterButtons()
     594{
     595    let resCodes = g_ResourceData.GetCodes();
     596    if (!g_BarterSell)
     597        g_BarterSell = resCodes[0];
     598
     599    let canBarter = GetSimState().players[g_ViewedPlayer].canBarter;
     600    Engine.GetGUIObjectByName("barterNoMarketsMessage").hidden = canBarter;
     601    Engine.GetGUIObjectByName("barterResources").hidden = !canBarter;
     602    if (!canBarter)
     603        return;
     604
     605    for (let i = 0; i < resCodes.length; ++i)
     606        barterUpdateCommon(resCodes[i], i, "barter", g_ViewedPlayer);
     607};
     608
    582609function getIdleLandTradersText(traderNumber)
    583610{
    584611    let active = traderNumber.landTrader.trading;
  • binaries/data/mods/public/gui/session/selection_panels.js

    diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js
    index 74789e0cd..2671da5e9 100644
    a b let g_FormationsInfo = new Map(); 
    3333
    3434let g_SelectionPanels = {};
    3535
    36 let g_BarterSell;
    37 
    3836g_SelectionPanels.Alert = {
    3937    "getMaxNumberOfItems": function()
    4038    {
    g_SelectionPanels.Barter = { 
    104102    "conflictsWith": ["Alert", "Garrison"],
    105103    "getItems": function(unitEntStates)
    106104    {
    107         if (unitEntStates.every(state => !state.barterMarket))
     105        // If more than {rowLength} resources, don't display icons
     106        if (unitEntStates.every(state => !state.isBarterMarket) || g_ResourceData.GetCodes().length > this.rowLength)
    108107            return [];
    109108        return g_ResourceData.GetCodes();
    110109    },
    111110    "setupButton": function(data)
    112111    {
    113         // data.item is the resource name in this case
    114         let button = {};
    115         let icon = {};
    116         let amount = {};
    117         for (let a of BARTER_ACTIONS)
    118         {
    119             button[a] = Engine.GetGUIObjectByName("unitBarter" + a + "Button[" + data.i + "]");
    120             icon[a] = Engine.GetGUIObjectByName("unitBarter" + a + "Icon[" + data.i + "]");
    121             amount[a] = Engine.GetGUIObjectByName("unitBarter" + a + "Amount[" + data.i + "]");
    122         }
    123         let selectionIcon = Engine.GetGUIObjectByName("unitBarterSellSelection[" + data.i + "]");
    124 
    125         let amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL;
    126         if (Engine.HotkeyIsPressed("session.massbarter"))
    127             amountToSell *= BARTER_BUNCH_MULTIPLIER;
    128 
    129         if (!g_BarterSell)
    130             g_BarterSell = g_ResourceData.GetCodes()[0];
    131 
    132         amount.Sell.caption = "-" + amountToSell;
    133         let prices;
    134         for (let state of data.unitEntStates)
    135             if (state.barterMarket)
    136             {
    137                 prices = state.barterMarket.prices;
    138                 break;
    139             }
    140 
    141         amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell);
    142 
    143         let resource = getLocalizedResourceName(g_ResourceData.GetNames()[data.item], "withinSentence");
    144         button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource });
    145         button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource });
     112        // Common stuff that only needs to be done when the panel is opened
     113        barterOpenCommon(data.item, data.i, "unitBarter", updateSelectionDetails);
    146114
    147         button.Sell.onPress = function() {
    148             g_BarterSell = data.item;
    149             updateSelectionDetails();
    150         };
    151 
    152         button.Buy.onPress = function() {
    153             Engine.PostNetworkCommand({
    154                 "type": "barter",
    155                 "sell": g_BarterSell,
    156                 "buy": data.item,
    157                 "amount": amountToSell
    158             });
    159         };
    160 
    161         let isSelected = data.item == g_BarterSell;
    162         let grayscale = isSelected ? "color: 0 0 0 100:grayscale:" : "";
     115        // Common stuff that needs to be done on simulation update
     116        barterUpdateCommon(data.item, data.i, "unitBarter", data.player);
    163117
    164         // do we have enough of this resource to sell?
    165         let neededRes = {};
    166         neededRes[data.item] = amountToSell;
    167         let canSellCurrent = Engine.GuiInterfaceCall("GetNeededResources", {
    168             "cost": neededRes,
    169             "player": data.player
    170         }) ? "color:255 0 0 80:" : "";
    171 
    172         // Let's see if we have enough resources to barter.
    173         neededRes = {};
    174         neededRes[g_BarterSell] = amountToSell;
    175         let canBuyAny = Engine.GuiInterfaceCall("GetNeededResources", {
    176             "cost": neededRes,
    177             "player": data.player
    178         }) ? "color:255 0 0 80:" : "";
    179 
    180         icon.Sell.sprite = canSellCurrent + "stretched:" + grayscale + "session/icons/resources/" + data.item + ".png";
    181         icon.Buy.sprite = canBuyAny + "stretched:" + grayscale + "session/icons/resources/" + data.item + ".png";
    182 
    183         button.Buy.hidden = isSelected;
    184         button.Buy.enabled = controlsPlayer(data.player);
    185         button.Sell.hidden = false;
    186         selectionIcon.hidden = !isSelected;
     118        // Final positioning
     119        let button = {};
     120        for (let action of BARTER_ACTIONS)
     121            button[action] = Engine.GetGUIObjectByName("unitBarter" + action + "Button[" + data.i + "]");
    187122
    188123        setPanelObjectPosition(button.Sell, data.i, data.rowLength);
    189124        setPanelObjectPosition(button.Buy, data.i + data.rowLength, data.rowLength);
    g_SelectionPanels.Upgrade = { 
    12461181 */
    12471182let g_PanelsOrder = [
    12481183    // LEFT PANE
    1249     "Barter", // Must always be visible on markets
     1184    "Barter", // Must always be visible on markets, if less than five resources
    12501185    "Garrison", // More important than Formation, as you want to see the garrisoned units in ships
    12511186    "Alert",
    12521187    "Formation",
  • binaries/data/mods/public/gui/session/selection_panels_helpers.js

    diff --git a/binaries/data/mods/public/gui/session/selection_panels_helpers.js b/binaries/data/mods/public/gui/session/selection_panels_helpers.js
    index 6b9f507d6..f817d9d7a 100644
    a b  
    1 const BARTER_RESOURCE_AMOUNT_TO_SELL = 100;
    2 const BARTER_BUNCH_MULTIPLIER = 5;
    3 const BARTER_ACTIONS = ["Sell", "Buy"];
    41const GATE_ACTIONS = ["lock", "unlock"];
    52
    63const UPGRADING_NOT_STARTED = -2;
    function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize 
    144141    }) + "[/font]";
    145142}
    146143
     144/**
     145 * Code common to both the Barter Panel and the Trade/Barter Dialog, that
     146 * only needs to be run when the panel or dialog is opened by the player.
     147 *
     148 * @param idx Element index within its set
     149 * @param prefix Common prefix of the gui elements to be worked upon
     150 * @param sellCallback The function to be called when the Sell button is pressed
     151 */
     152function barterOpenCommon(resourceCode, idx, prefix, sellCallback)
     153{
     154    let barterButton = {};
     155    for (let action of BARTER_ACTIONS)
     156        barterButton[action] = Engine.GetGUIObjectByName(prefix + action + "Button[" + idx + "]");
     157
     158    if (!g_BarterSell)
     159        g_BarterSell = g_ResourceData.GetCodes()[0];
     160
     161    let resource = getLocalizedResourceName(g_ResourceData.GetNames()[resourceCode], "withinSentence");
     162    barterButton.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource });
     163    barterButton.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource });
     164
     165    barterButton.Sell.onPress = function() {
     166        g_BarterSell = resourceCode;
     167        sellCallback();
     168    };
     169}
     170
    147171
     172/**
     173 * Code common to both the Barter Panel and the Trade/Barter Dialog, that
     174 * needs to be run on simulation update and when relevant hotkeys
     175 * (ie. `massbarter`) are pressed.
     176 *
     177 * @param idx Element index within its set
     178 * @param prefix Common prefix of the gui elements to be worked upon
     179 */
     180function barterUpdateCommon(resourceCode, idx, prefix, player)
     181{
     182    let barterButton = {};
     183    let barterIcon = {};
     184    let barterAmount = {};
     185    for (let action of BARTER_ACTIONS)
     186    {
     187        barterButton[action] = Engine.GetGUIObjectByName(prefix + action + "Button[" + idx + "]");
     188        barterIcon[action] = Engine.GetGUIObjectByName(prefix + action + "Icon[" + idx + "]");
     189        barterAmount[action] = Engine.GetGUIObjectByName(prefix + action + "Amount[" + idx + "]");
     190    }
     191    let selectionIcon = Engine.GetGUIObjectByName(prefix + "SellSelection[" + idx + "]");
     192
     193    let amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL;
     194    if (Engine.HotkeyIsPressed("session.massbarter"))
     195        amountToSell *= BARTER_BUNCH_MULTIPLIER;
     196
     197    let isSelected = resourceCode == g_BarterSell;
     198    let grayscale = isSelected ? "color:0 0 0 100:grayscale:" : "";
     199
     200    // Do we have enough of this resource to sell?
     201    let neededRes = {};
     202    neededRes[resourceCode] = amountToSell;
     203    let canSellCurrent = Engine.GuiInterfaceCall("GetNeededResources", {
     204        "cost": neededRes,
     205        "player": player
     206    }) ? "color:255 0 0 80:" : "";
     207
     208    // Let's see if we have enough resources to barter.
     209    neededRes = {};
     210    neededRes[g_BarterSell] = amountToSell;
     211    let canBuyAny = Engine.GuiInterfaceCall("GetNeededResources", {
     212        "cost": neededRes,
     213        "player": player
     214    }) ? "color:255 0 0 80:" : "";
     215
     216    barterIcon.Sell.sprite = canSellCurrent + "stretched:" + grayscale + "session/icons/resources/" + resourceCode + ".png";
     217    barterIcon.Buy.sprite = canBuyAny + "stretched:" + grayscale + "session/icons/resources/" + resourceCode + ".png";
     218
     219    barterAmount.Sell.caption = "-" + amountToSell;
     220    let prices = GetSimState().barterPrices;
     221    barterAmount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[resourceCode] * amountToSell);
     222
     223    barterButton.Buy.onPress = function() {
     224        Engine.PostNetworkCommand({
     225            "type": "barter",
     226            "sell": g_BarterSell,
     227            "buy": resourceCode,
     228            "amount": amountToSell
     229        });
     230    };
     231
     232    barterButton.Buy.hidden = isSelected;
     233    barterButton.Buy.enabled = controlsPlayer(player);
     234    barterButton.Sell.hidden = false;
     235    selectionIcon.hidden = !isSelected;
     236}
  • binaries/data/mods/public/gui/session/session.js

    diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js
    index d0b479581..12b817154 100644
    a b function updateGUIObjects() 
    771771    updateBuildingPlacementPreview();
    772772    updateTimeNotifications();
    773773    updateIdleWorkerButton();
     774    updateBarterButtons();
    774775
    775776    if (g_ViewedPlayer > 0)
    776777    {
  • binaries/data/mods/public/gui/session/top_panel/button_trade.xml

    diff --git a/binaries/data/mods/public/gui/session/top_panel/button_trade.xml b/binaries/data/mods/public/gui/session/top_panel/button_trade.xml
    index 787c1f760..6f59e92aa 100644
    a b  
    77>
    88    <!-- TODO make the button less ugly -->
    99    <object size="0 0 100% 100%" name="tradeButtonImage" type="image" sprite="stretched:session/icons/economics.png" ghost="true"/>
    10     <translatableAttribute id="tooltip">Trade</translatableAttribute>
     10    <translatableAttribute id="tooltip">Barter &amp; Trade</translatableAttribute>
    1111    <action on="Press">
    1212        toggleTrade();
    1313    </action>
  • binaries/data/mods/public/gui/session/trade_window.xml

    diff --git a/binaries/data/mods/public/gui/session/trade_window.xml b/binaries/data/mods/public/gui/session/trade_window.xml
    index 537eac505..f4d0d66de 100644
    a b  
    11<?xml version="1.0" encoding="utf-8"?>
    22<object name="tradeDialogPanel"
    3     size="50%-134 50%-130 50%+134 50%+100"
     3    size="50%-80 50%-280 50%+80 50%+136"
    44    type="image"
    55    hidden="true"
    66    sprite="ModernDialog"
     7    z="100"
    78>
    89    <object type="text" style="TitleText" size="50%-96 -16 50%+96 16">
    9         <translatableAttribute id="caption">Trade</translatableAttribute>
     10        <translatableAttribute id="caption">Barter &amp; Trade Goods</translatableAttribute>
    1011    </object>
    1112
    12     <!-- Trading goods -->
    13     <object name="tradeGoods" size="20 50 100%-20 82">
    14         <object name="tradeHeader" size="0 0 180 100%" type="text" style="ModernLabelText" text_align="left" ghost="true">
    15             <translatableAttribute id="caption">Trading goods selection:</translatableAttribute>
     13
     14    <!-- Barter Goods -->
     15    <object size="24 24 100%-24 33%">
     16
     17        <object name="barterHeader" size="8 0 100% 32" type="text" style="ModernLeftLabelText">
     18            <translatableAttribute id="caption">Barter</translatableAttribute>
    1619        </object>
     20        <object size="0 28 100% 29" type="image" sprite="ModernGoldLine"/>
     21
     22        <object size="0 38 100% 122">
     23
     24            <object size="0 0 60 41" type="text" style="ModernRightLabelText">
     25                <translatableAttribute id="caption">Sell:</translatableAttribute>
     26            </object>
     27
     28            <object size="0 100%-41 60 100%" type="text" style="ModernRightLabelText">
     29                <translatableAttribute id="caption">Buy:</translatableAttribute>
     30            </object>
     31
     32            <object size="72 0 100% 100%" type="text" style="ModernLabelText" name="barterNoMarketsMessage">
     33                <translatableAttribute id="caption">No Markets Available</translatableAttribute>
     34            </object>
     35
     36            <object name="barterResources" size="72 0 100% 100%">
     37                <repeat count="8">
     38                    <object name="barterResource[n]" size="0 0 58 100%">
     39
     40                        <!-- Sell -->
     41                        <object name="barterSellButton[n]" style="iconButton" type="button" size="0 0 41 41" tooltip_style="sessionToolTipBottomBold" hidden="true">
     42                            <object name="barterSellIcon[n]" type="image" ghost="true" size="3 3 100%-3 100%-3"/>
     43                            <object name="barterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
     44                            <object name="barterSellSelection[n]" hidden="true" type="image" ghost="true" size="3 3 100%-3 100%-3" sprite="stretched:session/icons/corners.png"/>
     45                        </object>
     46
     47                        <!-- Buy -->
     48                        <object name="barterBuyButton[n]" style="iconButton" type="button" size="0 100%-41 41 100%" tooltip_style="sessionToolTipBottomBold" hidden="true">
     49                            <object name="barterBuyIcon[n]" type="image" ghost="true" size="3 3 100%-3 100%-3"/>
     50                            <object name="barterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
     51                        </object>
    1752
    18         <object size="180 0 100% 100%" name="tradeResources">
    19             <repeat count="8">
    20                 <object name="tradeResource[n]" size="0 0 58 32">
    21                     <object name="tradeResourceButton[n]" size="4 0 36 100%" type="button" style="StoneButton">
    22                         <object name="tradeResourceIcon[n]" type="image" ghost="true"/>
    23                         <object name="tradeResourceSelection[n]" type="image" sprite="stretched:session/icons/corners.png" ghost="true"/>
    24                         <object name="tradeResourceText[n]" type="text" style="ModernLabelText" ghost="true"/>
    25                     </object>
    26                     <object name="tradeArrowUp[n]" size="36 0 52 50%" type="button" style="iconButton">
    27                         <object type="image" ghost="true" sprite="StoneArrowUp"/>
    2853                    </object>
    29                     <object name="tradeArrowDn[n]" size="36 50% 52 100%" type="button" style="iconButton">
    30                         <object type="image" ghost="true" sprite="StoneArrowDn"/>
     54                </repeat>
     55            </object>
     56
     57        </object>
     58    </object>
     59
     60    <!-- Trading goods -->
     61    <object size="24 33%+32 100%-24 100%-64">
     62
     63        <object name="tradeHeader" size="8 0 100% 32" type="text" style="ModernLeftLabelText">
     64            <translatableAttribute id="caption">Trade</translatableAttribute>
     65        </object>
     66        <object size="0 28 100% 29" type="image" sprite="ModernGoldLine"/>
     67
     68        <object name="tradeGoods" size="0 38 100% 70">
     69
     70            <object size="0 0 60 100%" type="text" style="ModernRightLabelText">
     71                <translatableAttribute id="caption">Goods:</translatableAttribute>
     72            </object>
     73
     74            <object size="72 0 100% 100%" name="tradeResources">
     75                <repeat count="8">
     76                    <object name="tradeResource[n]" size="0 0 58 32">
     77
     78                        <object name="tradeResourceButton[n]" size="4 0 36 100%" type="button" style="StoneButton">
     79                            <object name="tradeResourceIcon[n]" type="image" ghost="true"/>
     80                            <object name="tradeResourceSelection[n]" type="image" sprite="stretched:session/icons/corners.png" ghost="true"/>
     81                            <object name="tradeResourceText[n]" type="text" style="ModernLabelText" ghost="true"/>
     82                        </object>
     83                        <object name="tradeArrowUp[n]" size="36 0 52 50%" type="button" style="iconButton">
     84                            <object type="image" ghost="true" sprite="StoneArrowUp"/>
     85                        </object>
     86                        <object name="tradeArrowDn[n]" size="36 50% 52 100%" type="button" style="iconButton">
     87                            <object type="image" ghost="true" sprite="StoneArrowDn"/>
     88                        </object>
     89
    3190                    </object>
    32                 </object>
    33             </repeat>
     91                </repeat>
     92            </object>
     93
    3494            <object name="tradeHelp" size="100%-24 4 100% 28" enabled="false" type="button" style="StoneButton" tooltip_style="sessionToolTipBold">
    3595                <object size="20% 15% 80% 75%" type="image" ghost="true" sprite="iconInfoWhite"/>
    3696            </object>
     97
    3798        </object>
    38     </object>
    3999
    40     <object name="tradeStatistics" size="20 90 100%-20 168">
    41         <object name="landTraders" size="0 0 100% 50%" type="text" style="ModernLabelText" text_align="left" ghost="true" />
    42         <object name="shipTraders" size="0 50% 100% 100%" type="text" style="ModernLabelText" text_align="left" ghost="true" />
     100        <object name="traders" size="8 88 100% 100%" type="text" style="ModernLeftTabLabelText"/>
     101
    43102    </object>
    44103
    45104    <object size="50%-64 100%-50 50%+64 100%-22" type="button" style="StoneButton">
  • binaries/data/mods/public/gui/session/unit_actions.js

    diff --git a/binaries/data/mods/public/gui/session/unit_actions.js b/binaries/data/mods/public/gui/session/unit_actions.js
    index 85e7b050f..3f75ba5cf 100644
    a b var g_EntityCommands = 
    12601260                return false;
    12611261
    12621262            return {
    1263                 "tooltip": translate("Select trading goods"),
     1263                "tooltip": translate("Barter & Trade"),
    12641264                "icon": "economics.png"
    12651265            };
    12661266        },
  • binaries/data/mods/public/simulation/components/GuiInterface.js

    diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
    index 04ced0a3e..a9f0fa5d5 100644
    a b GuiInterface.prototype.GetSimulationState = function() 
    120120            "researchStarted": cmpTechnologyManager ? cmpTechnologyManager.GetStartedResearch() : null,
    121121            "researchedTechs": cmpTechnologyManager ? cmpTechnologyManager.GetResearchedTechs() : null,
    122122            "classCounts": cmpTechnologyManager ? cmpTechnologyManager.GetClassCounts() : null,
    123             "typeCountsByClass": cmpTechnologyManager ? cmpTechnologyManager.GetTypeCountsByClass() : null
     123            "typeCountsByClass": cmpTechnologyManager ? cmpTechnologyManager.GetTypeCountsByClass() : null,
     124            "canBarter": Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).PlayerHasMarket(playerEnt)
    124125        });
    125126    }
    126127
    GuiInterface.prototype.GetSimulationState = function() 
    150151    ret.alliedVictory = cmpEndGameManager.GetAlliedVictory();
    151152
    152153    // Add bartering prices
    153     let cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter);
    154     ret.barterPrices = cmpBarter.GetPrices();
     154    ret.barterPrices = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).GetPrices();
    155155
    156156    // Add Resource Codes, untranslated names and AI Analysis
    157157    ret.resources = {
    GuiInterface.prototype.GetExtendedEntityState = function(player, ent) 
    428428    let ret = {
    429429        "armour": null,
    430430        "attack": null,
    431         "barterMarket": null,
    432431        "buildingAI": null,
    433432        "heal": null,
     433        "isBarterMarket": null,
    434434        "loot": null,
    435435        "obstruction": null,
    436436        "turretParent":null,
    GuiInterface.prototype.GetExtendedEntityState = function(player, ent) 
    565565        };
    566566
    567567    if (!cmpFoundation && cmpIdentity && cmpIdentity.HasClass("BarterMarket"))
    568     {
    569         let cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter);
    570         ret.barterMarket = { "prices": cmpBarter.GetPrices() };
    571     }
     568        ret.isBarterMarket = true;
    572569
    573570    let cmpHeal = Engine.QueryInterface(ent, IID_Heal);
    574571    if (cmpHeal)
    GuiInterface.prototype.GetTradingGoods = function(player) 
    19541951    return QueryPlayerIDInterface(player).GetTradingGoods();
    19551952};
    19561953
     1954GuiInterface.prototype.PlayerCanBarter = function(player)
     1955{
     1956    let playerEnt = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetPlayerByID(player);
     1957    return Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter).PlayerHasMarket(playerEnt);
     1958};
     1959
    19571960GuiInterface.prototype.OnGlobalEntityRenamed = function(msg)
    19581961{
    19591962    this.renamedEntities.push(msg);
  • binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js

    diff --git a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
    index 3be85767c..39681883b 100644
    a b AddMock(SYSTEM_ENTITY, IID_Barter, { 
    5858            "buy": { "food": 150 },
    5959            "sell": { "food": 25 }
    6060        };
    61     }
     61    },
     62    PlayerHasMarket: function () { return false; }
    6263});
    6364
    6465AddMock(SYSTEM_ENTITY, IID_EndGameManager, {
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), { 
    290291            researchedTechs: {},
    291292            classCounts: {},
    292293            typeCountsByClass: {},
     294            canBarter: false,
    293295            statistics: {
    294296                resourcesGathered: {
    295297                    food: 100,
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), { 
    332334            researchedTechs: {},
    333335            classCounts: {},
    334336            typeCountsByClass: {},
     337            canBarter: false,
    335338            statistics: {
    336339                resourcesGathered: {
    337340                    food: 100,
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), { 
    402405            researchedTechs: {},
    403406            classCounts: {},
    404407            typeCountsByClass: {},
     408            canBarter: false,
    405409            statistics: {
    406410                unitsTrained: 10,
    407411                unitsLost: 9,
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), { 
    457461            researchedTechs: {},
    458462            classCounts: {},
    459463            typeCountsByClass: {},
     464            canBarter: false,
    460465            statistics: {
    461466                unitsTrained: 10,
    462467                unitsLost: 9,
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetEntityState(-1, 10), { 
    585590TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedEntityState(-1, 10), {
    586591    armour: null,
    587592    attack: null,
    588     barterMarket: {
    589         prices: { "buy": {"food":150}, "sell": {"food":25} },
    590     },
    591593    buildingAI: null,
    592594    heal: null,
     595    isBarterMarket: true,
    593596    loot: null,
    594597    obstruction: null,
    595598    turretParent: null,