Index: ps/trunk/binaries/data/config/default.cfg =================================================================== --- ps/trunk/binaries/data/config/default.cfg +++ ps/trunk/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 @@ -295,6 +293,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: ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml +++ ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml @@ -16,10 +16,14 @@ openChat(g_LastChatAddressee); - + toggleMenu(); + + toggleTrade(); + + var newSetting = !Engine.Renderer_GetSilhouettesEnabled(); @@ -72,8 +76,15 @@ - updateSelectionDetails(); - updateSelectionDetails(); + + updateSelectionDetails(); + updateBarterButtons(); + + + + updateSelectionDetails(); + updateBarterButtons(); + Index: ps/trunk/binaries/data/mods/public/gui/session/menu.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/menu.js +++ ps/trunk/binaries/data/mods/public/gui/session/menu.js @@ -28,6 +28,26 @@ // Shown in the trade dialog. const g_IdleTraderTextColor = "orange"; +/** + * Quantity of goods to sell per click. + */ +const g_BarterResourceSellQuantity = 100; + +/** + * Multiplier to be applied when holding the massbarter hotkey. + */ +const g_BarterMultiplier = 5; + +/** + * Barter actions, as mapped to the names of GUI Buttons. + */ +const g_BarterActions = ["Buy", "Sell"]; + +/** + * Currently selected resource type to sell in the barter GUI. + */ +var g_BarterSell; + var g_IsMenuOpen = false; var g_IsDiplomacyOpen = false; @@ -565,39 +585,51 @@ 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]; + + let barterResource = Engine.GetGUIObjectByName("barterResource[" + i + "]") + if (!barterResource) + { + warn("Current GUI limits prevent displaying more than " + i + " resources in the barter dialog!"); + break; + } + + // Barter: + barterOpenCommon(resCode, i, "barter"); + setPanelObjectPosition(barterResource, i, i+1); + + // Trade: let tradeResource = Engine.GetGUIObjectByName("tradeResource["+i+"]"); if (!tradeResource) { - warn("Current GUI limits prevent displaying more than " + r + " resources in the trading goods selection dialog!"); + warn("Current GUI limits prevent displaying more than " + i + " resources in the trading goods selection dialog!"); break; } 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"; @@ -611,10 +643,12 @@ "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){ - return function() { + buttonResource.onPress = (resource => { + return () => { if (Engine.HotkeyIsPressed("session.fulltradeswap")) { for (let res of resCodes) @@ -622,39 +656,152 @@ 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){ - return function() { - proba[resource] += Math.min(STEP, proba[selec]); - proba[selec] -= Math.min(STEP, proba[selec]); + buttonUp.onPress = (resource => { + return () => { + 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){ - return function() { - proba[selec] += Math.min(STEP, proba[resource]); + buttonDn.onPress = (resource => { + return () => { + 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(); - let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer); - Engine.GetGUIObjectByName("landTraders").caption = getIdleLandTradersText(traderNumber); - Engine.GetGUIObjectByName("shipTraders").caption = getIdleShipTradersText(traderNumber); + updateTradeButtons(); + updateTraderTexts(); + Engine.GetGUIObjectByName("tradeDialogPanel").hidden = false; } +function updateTraderTexts() +{ + let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer); + Engine.GetGUIObjectByName("traderCountText").caption = getIdleLandTradersText(traderNumber) + "\n\n" + getIdleShipTradersText(traderNumber); +} + +/** + * 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 {string} resourceCode + * @param {number} idx - Element index within its set + * @param {string} prefix - Common prefix of the gui elements to be worked upon + */ +function barterOpenCommon(resourceCode, idx, prefix) +{ + let barterButton = {}; + for (let action of g_BarterActions) + barterButton[action] = Engine.GetGUIObjectByName(prefix + action + "Button[" + idx + "]"); + + 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; + updateSelectionDetails(); + updateBarterButtons(); + }; +} + +/** + * Code common to both the Barter Panel and the Trade/Barter Dialog, that + * needs to be run on simulation update and when relevant hotkeys + * (i.e. massbarter) are pressed. + * + * @param {string} resourceCode + * @param {number} idx - Element index within its set + * @param {string} prefix - Common prefix of the gui elements to be worked upon + * @param {number} player + */ +function barterUpdateCommon(resourceCode, idx, prefix, player) +{ + let barterButton = {}; + let barterIcon = {}; + let barterAmount = {}; + for (let action of g_BarterActions) + { + 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 = g_BarterResourceSellQuantity; + if (Engine.HotkeyIsPressed("session.massbarter")) + amountToSell *= g_BarterMultiplier; + + let isSelected = resourceCode == g_BarterSell; + let grayscale = isSelected ? "color:0 0 0 100:grayscale:" : ""; + + // Select color of the sell button + let neededRes = {}; + neededRes[resourceCode] = amountToSell; + let canSellCurrent = Engine.GuiInterfaceCall("GetNeededResources", { + "cost": neededRes, + "player": player + }) ? "color:255 0 0 80:" : ""; + + // Select color of the buy button + 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; +} + +function updateBarterButtons() +{ + let canBarter = GetSimState().players[g_ViewedPlayer].canBarter; + Engine.GetGUIObjectByName("barterNoMarketsMessage").hidden = canBarter; + Engine.GetGUIObjectByName("barterResources").hidden = !canBarter; + Engine.GetGUIObjectByName("barterHelp").hidden = !canBarter; + + if (!canBarter) + return; + + let resCodes = g_ResourceData.GetCodes(); + for (let i = 0; i < resCodes.length; ++i) + barterUpdateCommon(resCodes[i], i, "barter", g_ViewedPlayer); +} + function getIdleLandTradersText(traderNumber) { let active = traderNumber.landTrader.trading; Index: ps/trunk/binaries/data/mods/public/gui/session/selection_panels.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/selection_panels.js +++ ps/trunk/binaries/data/mods/public/gui/session/selection_panels.js @@ -33,8 +33,6 @@ let g_SelectionPanels = {}; -let g_BarterSell; - g_SelectionPanels.Alert = { "getMaxNumberOfItems": function() { @@ -104,86 +102,19 @@ "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); + barterOpenCommon(data.item, data.i, "unitBarter"); + barterUpdateCommon(data.item, data.i, "unitBarter", data.player); - 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 }); - - 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:" : ""; - - // 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; + let button = {}; + for (let action of g_BarterActions) + 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); Index: ps/trunk/binaries/data/mods/public/gui/session/selection_panels_helpers.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/selection_panels_helpers.js +++ ps/trunk/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; Index: ps/trunk/binaries/data/mods/public/gui/session/session.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/session.js +++ ps/trunk/binaries/data/mods/public/gui/session/session.js @@ -271,6 +271,8 @@ g_CivData = loadCivData(); g_CivData.gaia = { "Code": "gaia", "Name": translate("Gaia") }; + g_BarterSell = g_ResourceData.GetCodes()[0]; + initializeMusic(); // before changing the perspective let gameSpeed = Engine.GetGUIObjectByName("gameSpeed"); @@ -398,6 +400,13 @@ Engine.GetGUIObjectByName("tradeHelp").tooltip = colorizeHotkey( translate("Select one type of goods you want to modify by clicking on it (Pressing %(hotkey)s while selecting will also bring its share to 100%%) and then use the arrows of the other types to modify their shares."), "session.fulltradeswap"); + + Engine.GetGUIObjectByName("barterHelp").tooltip = sprintf( + translate("Start by selecting the resource from the upper row that you wish to sell. Upon each press on one of the lower buttons, %(quantity)s of the upper resource will be sold for the displayed quantity of the lower. Press and hold %(hotkey)s to temporarily multiply all quantities by %(multiplier)s."), { + "quantity": g_BarterResourceSellQuantity, + "hotkey": colorizeHotkey("%(hotkey)s", "session.massbarter"), + "multiplier": g_BarterMultiplier + }); } function initGUIHeroes(slot) @@ -833,6 +842,12 @@ updateTimeNotifications(); updateIdleWorkerButton(); + if (g_IsTradeOpen) + { + updateTraderTexts(); + updateBarterButtons(); + } + if (g_ViewedPlayer > 0) { let playerState = GetSimState().players[g_ViewedPlayer]; Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_trade.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_trade.xml +++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_trade.xml @@ -5,9 +5,8 @@ style="iconButton" tooltip_style="sessionToolTip" > - - Trade + Barter & Trade toggleTrade(); Index: ps/trunk/binaries/data/mods/public/gui/session/trade_window.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/trade_window.xml +++ ps/trunk/binaries/data/mods/public/gui/session/trade_window.xml @@ -1,48 +1,111 @@