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 @@ -921,6 +921,45 @@ } }; +g_SelectionPanels.PrefAttack = { + "getMaxNumberOfItems": function() + { + return 4; + }, + "getItems": function(entStates) + { + if (entStates.some(state => !state.attack)) + return []; + + let items = ["Default"]; + for (let entState of entStates) + items = items.concat(Object.keys(entState.attack).filter( + type => items.indexOf(type) == -1 + )); + + // No point in showing only "Default" and one extra attack type. + return items.length > 2 ? items : ""; + }, + "setupButton": function(data) + { + let entIds = data.unitEntStates.map(state => state.id); + data.button.onPress = function() { performPrefAttack(entIds, data.item); }; + + data.button.tooltip = getPrefAttackDisplayName(data.item) + "\n" + + "[font=\"sans-13\"]" + getPrefAttackTooltip(data.item) + "[/font]"; + + data.guiSelection.hidden = !Engine.GuiInterfaceCall("IsPrefAttackSelected", { + "ents": entIds, + "prefAttack": data.item + }); + data.icon.sprite = "stretched:session/icons/attacks/" + data.item.toLowerCase() + ".png"; + data.button.enabled = controlsPlayer(data.player); + + setPanelObjectPosition(data.button, data.i, data.rowLength); + return true; + } +}; + g_SelectionPanels.Training = { "getMaxNumberOfItems": function() { @@ -1162,7 +1201,8 @@ "Garrison", // More important than Formation, as you want to see the garrisoned units in ships "Alert", "Formation", - "Stance", // Normal together with formation + "PrefAttack", // Normal together with formation and stance. + "Stance", // Normal together with formation and preferred attack. // RIGHT PANE "Gate", // Must always be shown on gates 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 @@ -87,6 +87,41 @@ } } +function getPrefAttackDisplayName(name) +{ + switch (name) + { + case "Default": + return translateWithContext("attack type", "Default"); + case "Capture": + return translateWithContext("attack type", "Capture"); + case "Ranged": + return translateWithContext("attack type", "Ranged"); + case "Melee": + return translateWithContext("attack type", "Melee"); + default: + warn("Internationalization: Unexpected attack type found: " + name); + return name; + } +} + +function getPrefAttackTooltip(name) +{ + switch (name) + { + case "Default": + return translateWithContext("attack type", "Let the unit decide."); + case "Capture": + return translateWithContext("attack type", "Prefer Capture attack."); + case "Ranged": + return translateWithContext("attack type", "Prefer Ranged attack."); + case "Melee": + return translateWithContext("attack type", "Prefer Melee attack."); + default: + return ""; + } +} + /** * Format entity count/limit message for the tooltip */ @@ -290,6 +325,18 @@ }); } +function performPrefAttack(entities, prefAttackType) +{ + if (!entities) + return; + + Engine.PostNetworkCommand({ + "type": "prefAttackType", + "entities": entities, + "name": prefAttackType + }); +} + function lockGate(lock) { Engine.PostNetworkCommand({ Index: binaries/data/mods/public/gui/session/selection_panels_left/attack_panel.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/session/selection_panels_left/attack_panel.xml @@ -0,0 +1,16 @@ + + + + + + Index: binaries/data/mods/public/gui/session/session.xml =================================================================== --- binaries/data/mods/public/gui/session/session.xml +++ binaries/data/mods/public/gui/session/session.xml @@ -120,7 +120,7 @@