diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index eb2929b95f..694cda0a97 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -363,7 +363,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ for(int id : unitIds){ Unit unit = Groups.unit.getByID(id); - if(unit != null && unit.team == player.team() && unit.controller() instanceof CommandAI ai){ + if(unit != null && unit.team == player.team() && unit.controller() instanceof CommandAI ai && unit.type.allowCommand(unit, command)){ boolean reset = command.resetTarget || ai.currentCommand().resetTarget; ai.command(command); if(reset){ @@ -372,7 +372,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } unit.lastCommanded = player.coloredName(); - //make sure its stance is valid + //make sure its current stance is valid with its current command stancesOut.clear(); unit.type.getUnitStances(unit, stancesOut); if(stancesOut.size > 0 && !stancesOut.contains(ai.stance)){ @@ -397,7 +397,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(unit != null && unit.team == player.team() && unit.controller() instanceof CommandAI ai){ if(stance == UnitStance.stop){ //not a real stance, just cancels orders ai.clearCommands(); - }else{ + }else if(unit.type.allowStance(unit, stance)){ ai.stance = stance; } unit.lastCommanded = player.coloredName(); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index ce323042e1..6f2b6d784b 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -44,6 +44,7 @@ import static mindustry.Vars.*; public class UnitType extends UnlockableContent implements Senseable{ public static final float shadowTX = -12, shadowTY = -13; private static final Vec2 legOffset = new Vec2(); + private static final Seq tmpStances = new Seq<>(); /** Environmental flags that are *all* required for this unit to function. 0 = any environment */ public int envRequired = 0; @@ -610,6 +611,17 @@ public class UnitType extends UnlockableContent implements Senseable{ } } + public boolean allowStance(Unit unit, UnitStance stance){ + if(stance == UnitStance.stop) return true; + tmpStances.clear(); + getUnitStances(unit, tmpStances); + return tmpStances.contains(stance); + } + + public boolean allowCommand(Unit unit, UnitCommand command){ + return commands.contains(command); + } + public void update(Unit unit){ } diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index 594301a15f..f83cf5d9ba 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -13,6 +13,7 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import mindustry.ai.*; +import mindustry.ai.types.*; import mindustry.content.*; import mindustry.core.*; import mindustry.entities.*; @@ -460,24 +461,31 @@ public class PlacementFragment{ commandTable.add(Core.bundle.get("commandmode.name")).fill().center().labelAlign(Align.center).row(); commandTable.image().color(Pal.accent).growX().pad(20f).padTop(0f).padBottom(4f).row(); commandTable.table(u -> { + + Bits activeCommands = new Bits(content.unitCommands().size); + Bits activeStances = new Bits(content.unitStances().size); + + Bits availableCommands = new Bits(content.unitCommands().size); + Bits availableStances = new Bits(content.unitStances().size); + u.left(); int[] curCount = {0}; - UnitCommand[] currentCommand = {null}; + Bits usedCommands = new Bits(content.unitCommands().size); var commands = new Seq(); - UnitStance[] currentStance = {null}; + Bits usedStances = new Bits(content.unitStances().size); var stances = new Seq(); - var stancesOut = new Seq(); rebuildCommand = () -> { u.clearChildren(); var units = control.input.selectedUnits; if(units.size > 0){ + usedCommands.clear(); + usedStances.clear(); commands.clear(); stances.clear(); - boolean firstCommand = false, firstStance = false; int[] counts = new int[content.units().size]; for(var unit : units){ @@ -486,12 +494,11 @@ public class PlacementFragment{ stancesOut.clear(); unit.type.getUnitStances(unit, stancesOut); - if(!firstStance){ - stances.add(stancesOut); - firstStance = true; - }else{ - //remove commands that this next unit type doesn't have - stances.removeAll(st -> !stancesOut.contains(st)); + for(var stance : stancesOut){ + if(!usedStances.get(stance.id)){ + stances.add(stance); + usedStances.set(stance.id); + } } } @@ -529,12 +536,11 @@ public class PlacementFragment{ unitlist.row(); } - if(!firstCommand){ - commands.add(type.commands); - firstCommand = true; - }else{ - //remove commands that this next unit type doesn't have - commands.removeAll(com -> !type.commands.contains(com)); + for(var command : type.commands){ + if(!usedCommands.get(command.id)){ + commands.add(command); + usedCommands.set(command.id); + } } } } @@ -548,8 +554,8 @@ public class PlacementFragment{ int scol = 0; for(var command : commands){ coms.button(Icon.icons.get(command.icon, Icon.cancel), Styles.clearNoneTogglei, () -> { - Call.setUnitCommand(player, units.mapInt(un -> un.id).toArray(), command); - }).checked(i -> currentCommand[0] == command).size(50f).tooltip(command.localized(), true); + Call.setUnitCommand(player, units.mapInt(un -> un.id, un -> un.type.allowCommand(un, command)).toArray(), command); + }).checked(i -> activeCommands.get(command.id)).size(50f).tooltip(command.localized(), true); if(++scol % 6 == 0) coms.row(); } @@ -571,8 +577,8 @@ public class PlacementFragment{ for(var stance : stances){ coms.button(stance.getIcon(), Styles.clearNoneTogglei, () -> { - Call.setUnitStance(player, units.mapInt(un -> un.id).toArray(), stance); - }).checked(i -> currentStance[0] == stance).size(50f).tooltip(stance.localized(), true); + Call.setUnitStance(player, units.mapInt(un -> un.id, un -> un.type.allowStance(un, stance)).toArray(), stance); + }).checked(i -> activeStances.get(stance.id)).size(50f).tooltip(stance.localized(), true); if(++scol % 6 == 0) coms.row(); } @@ -585,58 +591,50 @@ public class PlacementFragment{ u.update(() -> { { - boolean hadCommand = false, hadStance = false; - UnitCommand shareCommand = null; - UnitStance shareStance = null; + activeCommands.clear(); + activeStances.clear(); + availableCommands.clear(); + availableStances.clear(); //find the command that all units have, or null if they do not share one for(var unit : control.input.selectedUnits){ - if(unit.isCommandable()){ - var nextCommand = unit.command().command; + if(unit.controller() instanceof CommandAI cmd){ + activeCommands.set(cmd.command.id); + activeStances.set(cmd.stance.id); - if(hadCommand){ - if(shareCommand != nextCommand){ - shareCommand = null; - } - }else{ - shareCommand = nextCommand; - hadCommand = true; + for(var command : unit.type.commands){ + availableCommands.set(command.id); } - var nextStance = unit.command().stance; + stancesOut.clear(); + unit.type.getUnitStances(unit, stancesOut); - if(hadStance){ - if(shareStance != nextStance){ - shareStance = null; - } - }else{ - shareStance = nextStance; - hadStance = true; + for(var stance : stancesOut){ + availableStances.set(stance.id); } } } int size = control.input.selectedUnits.size; - if(curCount[0] != size || (currentCommand[0] != shareCommand && shareCommand != null && currentCommand[0] != null && (currentCommand[0].refreshOnSelect || shareCommand.refreshOnSelect))){ + if(curCount[0] != size || !usedCommands.equals(availableCommands) || !usedStances.equals(availableStances)){ + if(!(curCount[0] + size == 0)){ + rebuildCommand.run(); + } curCount[0] = size; - rebuildCommand.run(); } - currentCommand[0] = shareCommand; - currentStance[0] = shareStance; - //not a huge fan of running input logic here, but it's convenient as the stance arrays are all here... for(UnitStance stance : stances){ //first stance must always be the stop stance if(stance.keybind != null && Core.input.keyTap(stance.keybind)){ - Call.setUnitStance(player, control.input.selectedUnits.mapInt(un -> un.id).toArray(), stance); + Call.setUnitStance(player, control.input.selectedUnits.mapInt(un -> un.id, un -> un.type.allowStance(un, stance)).toArray(), stance); } } for(UnitCommand command : commands){ //first stance must always be the stop stance if(command.keybind != null && Core.input.keyTap(command.keybind)){ - Call.setUnitCommand(player, control.input.selectedUnits.mapInt(un -> un.id).toArray(), command); + Call.setUnitCommand(player, control.input.selectedUnits.mapInt(un -> un.id, un -> un.type.allowCommand(un, command)).toArray(), command); } } } diff --git a/gradle.properties b/gradle.properties index 63ab0424ce..0e14034a7f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=f3b1dc4a13 +archash=597a814beb