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 @@ -291,16 +291,13 @@ if (unitEntStates.some(state => !hasClass(state, "Unit"))) return []; + if(!canAllEntsUseAnyFormation()) + return []; + if (!g_AvailableFormations.has(unitEntStates[0].player)) g_AvailableFormations.set(unitEntStates[0].player, Engine.GuiInterfaceCall("GetAvailableFormations", unitEntStates[0].player)); - let availableFormations = g_AvailableFormations.get(unitEntStates[0].player); - - // Hide the panel if all formations are disabled - if (availableFormations.some(formation => canMoveSelectionIntoFormation(formation))) - return availableFormations; - - return []; + return g_AvailableFormations.get(unitEntStates[0].player); }, "setupButton": function(data) { 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 @@ -17,6 +17,13 @@ return g_canMoveIntoFormation[formationTemplate]; } +function canAllEntsUseAnyFormation() +{ + return Engine.GuiInterfaceCall("CanAllEntsUseAnyFormation", { + "ents": g_Selection.toList() + }); +} + function hasSameRestrictionCategory(templateName1, templateName2) { let template1 = GetTemplateData(templateName1); Index: binaries/data/mods/public/simulation/components/Formation.js =================================================================== --- binaries/data/mods/public/simulation/components/Formation.js +++ binaries/data/mods/public/simulation/components/Formation.js @@ -7,8 +7,12 @@ "" + "" + "" + - "" + - "" + + ""+ + ""+ + ""+ + "2"+ + ""+ + ""+ "" + "" + "" + @@ -75,6 +79,7 @@ Formation.prototype.Init = function() { + this.requiredMemberCount = this.template.RequiredMemberCount; this.formationShape = this.template.FormationShape; this.sortingClasses = this.template.SortingClasses.split(/\s+/g); this.sortingOrder = this.template.SortingOrder; @@ -325,16 +330,16 @@ this.members = this.members.filter(function(e) { return ents.indexOf(e) == -1; }); this.inPosition = this.inPosition.filter(function(e) { return ents.indexOf(e) == -1; }); - for (var ent of ents) + for (let ent of ents) { - var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); + let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); cmpUnitAI.UpdateWorkOrders(); cmpUnitAI.SetFormationController(INVALID_ENTITY); } - for (var ent of this.formationMembersWithAura) + for (let ent of this.formationMembersWithAura) { - var cmpAuras = Engine.QueryInterface(ent, IID_Auras); + let cmpAuras = Engine.QueryInterface(ent, IID_Auras); cmpAuras.RemoveFormationBonus(ents); // the unit with the aura is also removed from the formation @@ -344,10 +349,9 @@ this.formationMembersWithAura = this.formationMembersWithAura.filter(function(e) { return ents.indexOf(e) == -1; }); - // If there's nobody left, destroy the formation - if (this.members.length == 0) + if (this.members.length < this.requiredMemberCount) { - Engine.DestroyEntity(this.entity); + this.Disband(); return; } Index: binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- binaries/data/mods/public/simulation/components/GuiInterface.js +++ binaries/data/mods/public/simulation/components/GuiInterface.js @@ -714,6 +714,11 @@ return CanMoveEntsIntoFormation(data.ents, data.formationTemplate); }; +GuiInterface.prototype.CanAllEntsUseAnyFormation = function(player, data) +{ + return CanAllEntsUseAnyFormation(data.ents); +}; + GuiInterface.prototype.GetFormationInfoFromTemplate = function(player, data) { let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); @@ -1926,6 +1931,7 @@ "GetAvailableFormations": 1, "GetFormationRequirements": 1, "CanMoveEntsIntoFormation": 1, + "CanAllEntsUseAnyFormation": 1, "IsFormationSelected": 1, "GetFormationInfoFromTemplate": 1, "IsStanceSelected": 1, Index: binaries/data/mods/public/simulation/helpers/Commands.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Commands.js +++ binaries/data/mods/public/simulation/helpers/Commands.js @@ -1659,6 +1659,17 @@ return count >= requirements.minCount; } +function CanAllEntsUseAnyFormation(ents) +{ + for(let ent of ents) + { + let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); + if(!cmpIdentity || cmpIdentity.GetFormationsList().length == 0) + return false; + } + return true; +} + /** * Check if player can control this entity * returns: true if the entity is valid and owned by the player @@ -1721,6 +1732,7 @@ Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); +Engine.RegisterGlobal("CanAllEntsUseAnyFormation", CanAllEntsUseAnyFormation); Engine.RegisterGlobal("GetDockAngle", GetDockAngle); Engine.RegisterGlobal("ProcessCommand", ProcessCommand); Engine.RegisterGlobal("g_Commands", g_Commands); Index: binaries/data/mods/public/simulation/templates/special/formations/null.xml =================================================================== --- binaries/data/mods/public/simulation/templates/special/formations/null.xml +++ binaries/data/mods/public/simulation/templates/special/formations/null.xml @@ -3,5 +3,6 @@ formations/null.png None + Index: binaries/data/mods/public/simulation/templates/template_formation.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_formation.xml +++ binaries/data/mods/public/simulation/templates/template_formation.xml @@ -22,8 +22,8 @@ --> - 1 - + 2 + At least 2 units required 1 square Hero Champion Cavalry Melee Ranged