Index: binaries/data/config/default.cfg =================================================================== --- binaries/data/config/default.cfg +++ binaries/data/config/default.cfg @@ -157,8 +157,6 @@ fps.toggle = "Alt+F" ; Toggle frame counter realtime.toggle = "Alt+T" ; Toggle current display of computer time session.devcommands.toggle = "Alt+D" ; Toggle developer commands panel -session.gui.toggle = "Alt+G" ; Toggle visibility of session GUI -menu.toggle = "F10" ; Toggle in-game menu timeelapsedcounter.toggle = "F12" ; Toggle time elapsed counter session.showstatusbars = Tab ; Toggle display of status bars session.highlightguarding = PgDn ; Toggle highlight of guarding units @@ -294,6 +292,11 @@ rotate.cw = RightBracket ; Rotate building placement preview clockwise rotate.ccw = LeftBracket ; Rotate building placement preview anticlockwise +[hotkey.session.gui] +toggle = "Alt+G" ; Toggle visibility of session GUI +menu.toggle = "F10" ; Toggle in-game menu +barter.toggle = "Ctrl+B" ; Toggle in-game barter/trade page + [hotkey.session.savedgames] delete = Delete ; Delete the selected saved game asking confirmation noconfirmation = Shift ; Do not ask confirmation when deleting a game Index: binaries/data/mods/public/gui/session/hotkeys/misc.xml =================================================================== --- binaries/data/mods/public/gui/session/hotkeys/misc.xml +++ binaries/data/mods/public/gui/session/hotkeys/misc.xml @@ -12,10 +12,14 @@ openChat(true); - + toggleMenu(); + + toggleTrade(); + + var newSetting = !Engine.Renderer_GetSilhouettesEnabled(); @@ -68,8 +72,14 @@ - updateSelectionDetails(); - updateSelectionDetails(); + + updateSelectionDetails(); + updateBarterButtons(); + + + updateSelectionDetails(); + updateBarterButtons(); + Index: binaries/data/mods/public/gui/session/menu.js =================================================================== --- binaries/data/mods/public/gui/session/menu.js +++ binaries/data/mods/public/gui/session/menu.js @@ -28,6 +28,11 @@ // Shown in the trade dialog. const g_IdleTraderTextColor = "orange"; +const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; +const BARTER_BUNCH_MULTIPLIER = 5; +const BARTER_ACTIONS = ["Buy", "Sell"]; +var g_BarterSell; + var g_IsMenuOpen = false; var g_IsDiplomacyOpen = false; @@ -489,27 +494,35 @@ g_IsTradeOpen = true; - var updateButtons = function() + let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer); + let button = {}; + let resCodes = g_ResourceData.GetCodes(); + let currTradeSelection = resCodes[0]; + + let updateTradeButtons = function() { for (let res in button) { button[res].label.caption = proba[res] + "%"; - button[res].sel.hidden = !controlsPlayer(g_ViewedPlayer) || res != selec; - button[res].up.hidden = !controlsPlayer(g_ViewedPlayer) || res == selec || proba[res] == 100 || proba[selec] == 0; - button[res].dn.hidden = !controlsPlayer(g_ViewedPlayer) || res == selec || proba[res] == 0 || proba[selec] == 100; + button[res].sel.hidden = !controlsPlayer(g_ViewedPlayer) || res != currTradeSelection; + button[res].up.hidden = !controlsPlayer(g_ViewedPlayer) || res == currTradeSelection || proba[res] == 100 || proba[currTradeSelection] == 0; + button[res].dn.hidden = !controlsPlayer(g_ViewedPlayer) || res == currTradeSelection || proba[res] == 0 || proba[currTradeSelection] == 100; } }; - let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer); - let button = {}; - let resCodes = g_ResourceData.GetCodes(); - let selec = resCodes[0]; hideRemaining("tradeResources", resCodes.length); Engine.GetGUIObjectByName("tradeHelp").hidden = false; for (let i = 0; i < resCodes.length; ++i) { + let resCode = resCodes[i]; + + // Barter + barterOpenCommon(resCode, i, "barter", updateBarterButtons); + setPanelObjectPosition(Engine.GetGUIObjectByName("barterResource[" + i + "]"), i, i+1); + + // Trade let tradeResource = Engine.GetGUIObjectByName("tradeResource["+i+"]"); if (!tradeResource) { @@ -519,9 +532,6 @@ setPanelObjectPosition(tradeResource, i, i+1); - let resCode = resCodes[i]; - proba[resCode] = proba[resCode] || 0; - let icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]"); icon.sprite = "stretched:session/icons/resources/" + resCode + ".png"; @@ -535,9 +545,11 @@ "sel": Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]") }; + proba[resCode] = proba[resCode] || 0; + let buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]"); buttonResource.enabled = controlsPlayer(g_ViewedPlayer); - buttonResource.onpress = (function(resource){ + buttonResource.onPress = (function(resource){ return function() { if (Engine.HotkeyIsPressed("session.fulltradeswap")) { @@ -546,39 +558,54 @@ proba[resource] = 100; Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); } - selec = resource; - updateButtons(); + currTradeSelection = resource; + updateTradeButtons(); }; })(resCode); buttonUp.enabled = controlsPlayer(g_ViewedPlayer); - buttonUp.onpress = (function(resource){ + buttonUp.onPress = (function(resource){ return function() { - proba[resource] += Math.min(STEP, proba[selec]); - proba[selec] -= Math.min(STEP, proba[selec]); + proba[resource] += Math.min(STEP, proba[currTradeSelection]); + proba[currTradeSelection] -= Math.min(STEP, proba[currTradeSelection]); Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); - updateButtons(); + updateTradeButtons(); }; })(resCode); buttonDn.enabled = controlsPlayer(g_ViewedPlayer); - buttonDn.onpress = (function(resource){ + buttonDn.onPress = (function(resource){ return function() { - proba[selec] += Math.min(STEP, proba[resource]); + proba[currTradeSelection] += Math.min(STEP, proba[resource]); proba[resource] -= Math.min(STEP, proba[resource]); Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); - updateButtons(); + updateTradeButtons(); }; })(resCode); } - updateButtons(); + updateTradeButtons(); let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer); - Engine.GetGUIObjectByName("landTraders").caption = getIdleLandTradersText(traderNumber); - Engine.GetGUIObjectByName("shipTraders").caption = getIdleShipTradersText(traderNumber); + Engine.GetGUIObjectByName("traders").caption = getIdleLandTradersText(traderNumber) + "\n\n" + getIdleShipTradersText(traderNumber); Engine.GetGUIObjectByName("tradeDialogPanel").hidden = false; } +function updateBarterButtons() +{ + let resCodes = g_ResourceData.GetCodes(); + if (!g_BarterSell) + g_BarterSell = resCodes[0]; + + let canBarter = GetSimState().players[g_ViewedPlayer].canBarter; + Engine.GetGUIObjectByName("barterNoMarketsMessage").hidden = canBarter; + Engine.GetGUIObjectByName("barterResources").hidden = !canBarter; + if (!canBarter) + return; + + for (let i = 0; i < resCodes.length; ++i) + barterUpdateCommon(resCodes[i], i, "barter", g_ViewedPlayer); +}; + function getIdleLandTradersText(traderNumber) { let active = traderNumber.landTrader.trading; Index: binaries/data/mods/public/gui/session/selection_panels.js =================================================================== --- binaries/data/mods/public/gui/session/selection_panels.js +++ binaries/data/mods/public/gui/session/selection_panels.js @@ -33,8 +33,6 @@ let g_SelectionPanels = {}; -let g_BarterSell; - function getPlayerHighlightColor(player) { return "color:" + rgbToGuiColor(g_Players[player].color) + " 160"; @@ -109,86 +107,23 @@ "conflictsWith": ["Alert", "Garrison"], "getItems": function(unitEntStates) { - if (unitEntStates.every(state => !state.barterMarket)) + // If more than {rowLength} resources, don't display icons + if (unitEntStates.every(state => !state.isBarterMarket) || g_ResourceData.GetCodes().length > this.rowLength) return []; return g_ResourceData.GetCodes(); }, "setupButton": function(data) { - // data.item is the resource name in this case - let button = {}; - let icon = {}; - let amount = {}; - for (let a of BARTER_ACTIONS) - { - button[a] = Engine.GetGUIObjectByName("unitBarter" + a + "Button[" + data.i + "]"); - icon[a] = Engine.GetGUIObjectByName("unitBarter" + a + "Icon[" + data.i + "]"); - amount[a] = Engine.GetGUIObjectByName("unitBarter" + a + "Amount[" + data.i + "]"); - } - let selectionIcon = Engine.GetGUIObjectByName("unitBarterSellSelection[" + data.i + "]"); - - let amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL; - if (Engine.HotkeyIsPressed("session.massbarter")) - amountToSell *= BARTER_BUNCH_MULTIPLIER; - - if (!g_BarterSell) - g_BarterSell = g_ResourceData.GetCodes()[0]; - - amount.Sell.caption = "-" + amountToSell; - let prices; - for (let state of data.unitEntStates) - if (state.barterMarket) - { - prices = state.barterMarket.prices; - break; - } - - amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell); - - let resource = getLocalizedResourceName(g_ResourceData.GetNames()[data.item], "withinSentence"); - button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource }); - button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource }); + // Common stuff that only needs to be done when the panel is opened + barterOpenCommon(data.item, data.i, "unitBarter", updateSelectionDetails); - button.Sell.onPress = function() { - g_BarterSell = data.item; - updateSelectionDetails(); - }; - - button.Buy.onPress = function() { - Engine.PostNetworkCommand({ - "type": "barter", - "sell": g_BarterSell, - "buy": data.item, - "amount": amountToSell - }); - }; - - let isSelected = data.item == g_BarterSell; - let grayscale = isSelected ? "color: 0 0 0 100:grayscale:" : ""; + // Common stuff that needs to be done on simulation update + barterUpdateCommon(data.item, data.i, "unitBarter", data.player); - // do we have enough of this resource to sell? - let neededRes = {}; - neededRes[data.item] = amountToSell; - let canSellCurrent = Engine.GuiInterfaceCall("GetNeededResources", { - "cost": neededRes, - "player": data.player - }) ? "color:255 0 0 80:" : ""; - - // Let's see if we have enough resources to barter. - neededRes = {}; - neededRes[g_BarterSell] = amountToSell; - let canBuyAny = Engine.GuiInterfaceCall("GetNeededResources", { - "cost": neededRes, - "player": data.player - }) ? "color:255 0 0 80:" : ""; - - icon.Sell.sprite = canSellCurrent + "stretched:" + grayscale + "session/icons/resources/" + data.item + ".png"; - icon.Buy.sprite = canBuyAny + "stretched:" + grayscale + "session/icons/resources/" + data.item + ".png"; - - button.Buy.hidden = isSelected; - button.Buy.enabled = controlsPlayer(data.player); - button.Sell.hidden = false; - selectionIcon.hidden = !isSelected; + // Final positioning + let button = {}; + for (let action of BARTER_ACTIONS) + button[action] = Engine.GetGUIObjectByName("unitBarter" + action + "Button[" + data.i + "]"); setPanelObjectPosition(button.Sell, data.i, data.rowLength); setPanelObjectPosition(button.Buy, data.i + data.rowLength, data.rowLength); @@ -1253,7 +1188,7 @@ */ let g_PanelsOrder = [ // LEFT PANE - "Barter", // Must always be visible on markets + "Barter", // Must always be visible on markets, if less than five resources "Garrison", // More important than Formation, as you want to see the garrisoned units in ships "Alert", "Formation", Index: binaries/data/mods/public/gui/session/selection_panels_helpers.js =================================================================== --- binaries/data/mods/public/gui/session/selection_panels_helpers.js +++ binaries/data/mods/public/gui/session/selection_panels_helpers.js @@ -1,6 +1,3 @@ -const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; -const BARTER_BUNCH_MULTIPLIER = 5; -const BARTER_ACTIONS = ["Sell", "Buy"]; const GATE_ACTIONS = ["lock", "unlock"]; const UPGRADING_NOT_STARTED = -2; @@ -144,4 +141,96 @@ }) + "[/font]"; } +/** + * Code common to both the Barter Panel and the Trade/Barter Dialog, that + * only needs to be run when the panel or dialog is opened by the player. + * + * @param idx Element index within its set + * @param prefix Common prefix of the gui elements to be worked upon + * @param sellCallback The function to be called when the Sell button is pressed + */ +function barterOpenCommon(resourceCode, idx, prefix, sellCallback) +{ + let barterButton = {}; + for (let action of BARTER_ACTIONS) + barterButton[action] = Engine.GetGUIObjectByName(prefix + action + "Button[" + idx + "]"); + + if (!g_BarterSell) + g_BarterSell = g_ResourceData.GetCodes()[0]; + + let resource = getLocalizedResourceName(g_ResourceData.GetNames()[resourceCode], "withinSentence"); + barterButton.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource }); + barterButton.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource }); + + barterButton.Sell.onPress = function() { + g_BarterSell = resourceCode; + sellCallback(); + }; +} + +/** + * Code common to both the Barter Panel and the Trade/Barter Dialog, that + * needs to be run on simulation update and when relevant hotkeys + * (ie. `massbarter`) are pressed. + * + * @param idx Element index within its set + * @param prefix Common prefix of the gui elements to be worked upon + */ +function barterUpdateCommon(resourceCode, idx, prefix, player) +{ + let barterButton = {}; + let barterIcon = {}; + let barterAmount = {}; + for (let action of BARTER_ACTIONS) + { + barterButton[action] = Engine.GetGUIObjectByName(prefix + action + "Button[" + idx + "]"); + barterIcon[action] = Engine.GetGUIObjectByName(prefix + action + "Icon[" + idx + "]"); + barterAmount[action] = Engine.GetGUIObjectByName(prefix + action + "Amount[" + idx + "]"); + } + let selectionIcon = Engine.GetGUIObjectByName(prefix + "SellSelection[" + idx + "]"); + + let amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL; + if (Engine.HotkeyIsPressed("session.massbarter")) + amountToSell *= BARTER_BUNCH_MULTIPLIER; + + let isSelected = resourceCode == g_BarterSell; + let grayscale = isSelected ? "color:0 0 0 100:grayscale:" : ""; + + // Do we have enough of this resource to sell? + let neededRes = {}; + neededRes[resourceCode] = amountToSell; + let canSellCurrent = Engine.GuiInterfaceCall("GetNeededResources", { + "cost": neededRes, + "player": player + }) ? "color:255 0 0 80:" : ""; + + // Let's see if we have enough resources to barter. + neededRes = {}; + neededRes[g_BarterSell] = amountToSell; + let canBuyAny = Engine.GuiInterfaceCall("GetNeededResources", { + "cost": neededRes, + "player": player + }) ? "color:255 0 0 80:" : ""; + + barterIcon.Sell.sprite = canSellCurrent + "stretched:" + grayscale + "session/icons/resources/" + resourceCode + ".png"; + barterIcon.Buy.sprite = canBuyAny + "stretched:" + grayscale + "session/icons/resources/" + resourceCode + ".png"; + + barterAmount.Sell.caption = "-" + amountToSell; + let prices = GetSimState().barterPrices; + barterAmount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[resourceCode] * amountToSell); + + barterButton.Buy.onPress = function() { + Engine.PostNetworkCommand({ + "type": "barter", + "sell": g_BarterSell, + "buy": resourceCode, + "amount": amountToSell + }); + }; + + barterButton.Buy.hidden = isSelected; + barterButton.Buy.enabled = controlsPlayer(player); + barterButton.Sell.hidden = false; + selectionIcon.hidden = !isSelected; +} Index: binaries/data/mods/public/gui/session/session.js =================================================================== --- binaries/data/mods/public/gui/session/session.js +++ binaries/data/mods/public/gui/session/session.js @@ -771,6 +771,7 @@ updateBuildingPlacementPreview(); updateTimeNotifications(); updateIdleWorkerButton(); + updateBarterButtons(); if (g_ViewedPlayer > 0) { Index: binaries/data/mods/public/gui/session/top_panel/button_trade.xml =================================================================== --- binaries/data/mods/public/gui/session/top_panel/button_trade.xml +++ binaries/data/mods/public/gui/session/top_panel/button_trade.xml @@ -7,7 +7,7 @@ > - Trade + Barter & Trade toggleTrade(); Index: binaries/data/mods/public/gui/session/trade_window.xml =================================================================== --- binaries/data/mods/public/gui/session/trade_window.xml +++ binaries/data/mods/public/gui/session/trade_window.xml @@ -1,45 +1,104 @@