diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js index eff65c0f30..b1a3ec1554 100644 --- a/binaries/data/mods/public/gui/session/input.js +++ b/binaries/data/mods/public/gui/session/input.js @@ -1581,7 +1581,7 @@ function performCommand(entity, commandName) preSelectedAction = ACTION_REPAIR; break; case "unload-all": - unloadAll(entity); + unloadAll(); break; case "focus-rally": // if the selected building has a rally point set, move the camera to it; otherwise, move to the building itself @@ -1768,7 +1768,33 @@ function unload(garrisonHolder, entities) Engine.PostNetworkCommand({"type": "unload", "entities": [entities[0]], "garrisonHolder": garrisonHolder}); } -function unloadAll(garrisonHolder) +function unloadTemplate(template) { - Engine.PostNetworkCommand({"type": "unload-all", "garrisonHolder": garrisonHolder}); + // Filter out all entities that aren't garrisonable. + var garrisonHolders = g_Selection.toList().filter(function(e) { + var state = GetEntityState(e); + if (state && state.garrisonHolder) + return true; + return false; + }); + + Engine.PostNetworkCommand({ + "type": "unload-template", + "all": Engine.HotkeyIsPressed("session.unloadtype"), + "template": template, + "garrisonHolders": garrisonHolders + }); +} + +function unloadAll() +{ + // Filter out all entities that aren't garrisonable. + var garrisonHolders = g_Selection.toList().filter(function(e) { + var state = GetEntityState(e); + if (state && state.garrisonHolder) + return true; + return false; + }); + + Engine.PostNetworkCommand({"type": "unload-all", "garrisonHolders": garrisonHolders}); } diff --git a/binaries/data/mods/public/gui/session/unit_commands.js b/binaries/data/mods/public/gui/session/unit_commands.js index 5b223b3eb9..8f66e245c7 100644 --- a/binaries/data/mods/public/gui/session/unit_commands.js +++ b/binaries/data/mods/public/gui/session/unit_commands.js @@ -174,8 +174,6 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback) case GARRISON: if (numberOfItems > 16) numberOfItems = 16; - //Group garrisoned units based on class - garrisonGroups.add(unitEntState.garrisonHolder.entities); break; case STANCE: @@ -217,6 +215,23 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback) break; } + switch (guiName) + { + case GARRISON: + case COMMAND: + // Common code for garrison and 'unload all' button counts. + for (var i = 0; i < selection.length; ++i) + { + var state = GetEntityState(selection[i]); + if (state.garrisonHolder) + garrisonGroups.add(state.garrisonHolder.entities) + } + break; + + default: + break; + } + var rowLength = 8; if (guiName == SELECTION) rowLength = 4; @@ -411,7 +426,7 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback) // here, "item" is an object with properties .name (command name), .tooltip and .icon (relative to session/icons/single) if (item.name == "unload-all") { - var count = unitEntState.garrisonHolder.entities.length; + var count = garrisonGroups.getTotalCount(); getGUIObjectByName("unit"+guiName+"Count["+i+"]").caption = (count > 0 ? count : ""); } else @@ -859,9 +874,15 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s if (entState.garrisonHolder) { var groups = new EntityGroups(); - groups.add(entState.garrisonHolder.entities); + for (var i in selection) + { + state = GetEntityState(selection[i]); + if (state.garrisonHolder) + groups.add(state.garrisonHolder.entities) + } + setupUnitPanel(GARRISON, usedPanels, entState, groups.getTemplateNames(), - function (item) { unload(entState.id, groups.getEntsByName(item)); } ); + function (item) { unloadTemplate(item); } ); } var formations = Engine.GuiInterfaceCall("GetAvailableFormations"); diff --git a/binaries/data/mods/public/simulation/components/GarrisonHolder.js b/binaries/data/mods/public/simulation/components/GarrisonHolder.js index 97573675bf..0b6206e684 100644 --- a/binaries/data/mods/public/simulation/components/GarrisonHolder.js +++ b/binaries/data/mods/public/simulation/components/GarrisonHolder.js @@ -244,6 +244,50 @@ GarrisonHolder.prototype.Unload = function(entity, forced) return false; }; +/** + * Unload one or all units that match a template from the + * garrisoning entity and order them to move to the Rally Point + * Returns true if successful, false if not + */ +GarrisonHolder.prototype.UnloadTemplate = function(template, all, forced) +{ + var ejectedEntities = []; + var success = true; + for (var i = 0; i < this.entities.length; ++i) + { + var entity = this.entities[i]; + var cmpIdentity = Engine.QueryInterface(entity, IID_Identity); + + // Units with multiple ranks are grouped together. + var name = cmpIdentity.GetSelectionGroupName(); + if (!name) + { + var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); + name = cmpTemplateManager.GetCurrentTemplateName(entity); + } + + if (name != template) + continue; + + if (this.Eject(entity, forced)) + { + --i; // Decrement 'i' as Eject() shortens the array. + ejectedEntities.push(entity); + + // If 'all' is false, only ungarrison the first matched unit. + if (!all) + break; + } + else + success = false; + } + + this.OrderWalkToRallyPoint(ejectedEntities); + this.UpdateGarrisonFlag(); + + return success; +}; + /** * Unload all units from the entity * Returns true if all successful, false if not diff --git a/binaries/data/mods/public/simulation/helpers/Commands.js b/binaries/data/mods/public/simulation/helpers/Commands.js index c3698fc803..e60ef40b89 100644 --- a/binaries/data/mods/public/simulation/helpers/Commands.js +++ b/binaries/data/mods/public/simulation/helpers/Commands.js @@ -289,19 +289,11 @@ function ProcessCommand(player, cmd) var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder); var notUngarrisoned = 0; for each (ent in cmd.entities) - { if (!cmpGarrisonHolder || !cmpGarrisonHolder.Unload(ent)) - { notUngarrisoned++; - } - } + if (notUngarrisoned != 0) - { - var cmpPlayer = QueryPlayerIDInterface(player, IID_Player); - var notification = {"player": cmpPlayer.GetPlayerID(), "message": (notUngarrisoned == 1 ? "Unable to ungarrison unit" : "Unable to ungarrison units")}; - var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); - cmpGUIInterface.PushNotification(notification); - } + notifyUnloadFailure(player, cmd.garrisonHolder) } else if (g_DebugCommands) { @@ -309,22 +301,23 @@ function ProcessCommand(player, cmd) } break; - case "unload-all": - // Verify that the building can be controlled by the player - if (CanControlUnit(cmd.garrisonHolder, player, controlAllUnits)) + case "unload-template": + var selected = FilterEntityList(cmd.garrisonHolders, player, controlAllUnits); + for each (var garrisonHolder in selected) { - var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder); - if (!cmpGarrisonHolder || !cmpGarrisonHolder.UnloadAll()) - { - var cmpPlayer = QueryPlayerIDInterface(player, IID_Player); - var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Unable to ungarrison all units"}; - var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); - cmpGUIInterface.PushNotification(notification); - } + var cmpGarrisonHolder = Engine.QueryInterface(garrisonHolder, IID_GarrisonHolder); + if (!cmpGarrisonHolder || !cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.all)) + notifyUnloadFailure(player, garrisonHolder) } - else if (g_DebugCommands) + break; + + case "unload-all": + var selected = FilterEntityList(cmd.garrisonHolders, player, controlAllUnits); + for each (var garrisonHolder in selected) { - warn("Invalid command: unload-all target cannot be controlled by player "+player+": "+uneval(cmd)); + var cmpGarrisonHolder = Engine.QueryInterface(garrisonHolder, IID_GarrisonHolder); + if (!cmpGarrisonHolder || !cmpGarrisonHolder.UnloadAll()) + notifyUnloadFailure(player, garrisonHolder) } break; @@ -423,6 +416,17 @@ function ProcessCommand(player, cmd) } } +/** + * Sends a GUI notification about unit(s) that failed to ungarrison. + */ +function notifyUnloadFailure(player, garrisonHolder) +{ + var cmpPlayer = QueryPlayerIDInterface(player, IID_Player); + var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Unable to ungarrison unit(s)" }; + var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); + cmpGUIInterface.PushNotification(notification); +} + /** * Get some information about the formations used by entities. * The entities must have a UnitAI component.