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,44 @@ } }; +g_SelectionPanels.PrefAttack = { + "getMaxNumberOfItems": function() + { + return 4; + }, + "getItems": function(unitEntStates) + { + if (unitEntStates.some(state => !state.attack || !hasClass(state, "Unit") || hasClass(state, "Animal"))) + return []; + + let items = ["Default"]; + for (let unitEntState of unitEntStates) + items = items.concat(Object.keys(unitEntState.attack).filter( + type => items.indexOf(type) == -1 + )); + + return items; + }, + "setupButton": function(data) + { + let unitIds = data.unitEntStates.map(state => state.id); + data.button.onPress = function() { performPrefAttack(unitIds, data.item); }; + + data.button.tooltip = getPrefAttackDisplayName(data.item) + "\n" + + "[font=\"sans-13\"]" + getPrefAttackTooltip(data.item) + "[/font]"; + + data.guiSelection.hidden = !Engine.GuiInterfaceCall("IsPrefAttackSelected", { + "ents": unitIds, + "prefAttack": data.item + }); + data.icon.sprite = "stretched:session/icons/stances/" + data.item + ".png"; + data.button.enabled = controlsPlayer(data.player); + + setPanelObjectPosition(data.button, data.i, data.rowLength); + return true; + } +}; + g_SelectionPanels.Training = { "getMaxNumberOfItems": function() { @@ -1162,7 +1200,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 @@