Allow commands/stances even when units do not have them in common

This commit is contained in:
Anuken
2025-04-28 16:25:44 -04:00
parent 52141c442f
commit ca550545bc
4 changed files with 61 additions and 51 deletions

View File

@@ -363,7 +363,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
for(int id : unitIds){ for(int id : unitIds){
Unit unit = Groups.unit.getByID(id); 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; boolean reset = command.resetTarget || ai.currentCommand().resetTarget;
ai.command(command); ai.command(command);
if(reset){ if(reset){
@@ -372,7 +372,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
unit.lastCommanded = player.coloredName(); unit.lastCommanded = player.coloredName();
//make sure its stance is valid //make sure its current stance is valid with its current command
stancesOut.clear(); stancesOut.clear();
unit.type.getUnitStances(unit, stancesOut); unit.type.getUnitStances(unit, stancesOut);
if(stancesOut.size > 0 && !stancesOut.contains(ai.stance)){ 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(unit != null && unit.team == player.team() && unit.controller() instanceof CommandAI ai){
if(stance == UnitStance.stop){ //not a real stance, just cancels orders if(stance == UnitStance.stop){ //not a real stance, just cancels orders
ai.clearCommands(); ai.clearCommands();
}else{ }else if(unit.type.allowStance(unit, stance)){
ai.stance = stance; ai.stance = stance;
} }
unit.lastCommanded = player.coloredName(); unit.lastCommanded = player.coloredName();

View File

@@ -44,6 +44,7 @@ import static mindustry.Vars.*;
public class UnitType extends UnlockableContent implements Senseable{ public class UnitType extends UnlockableContent implements Senseable{
public static final float shadowTX = -12, shadowTY = -13; public static final float shadowTX = -12, shadowTY = -13;
private static final Vec2 legOffset = new Vec2(); private static final Vec2 legOffset = new Vec2();
private static final Seq<UnitStance> tmpStances = new Seq<>();
/** Environmental flags that are *all* required for this unit to function. 0 = any environment */ /** Environmental flags that are *all* required for this unit to function. 0 = any environment */
public int envRequired = 0; 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){ public void update(Unit unit){
} }

View File

@@ -13,6 +13,7 @@ import arc.scene.ui.layout.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.ai.*; import mindustry.ai.*;
import mindustry.ai.types.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.core.*; import mindustry.core.*;
import mindustry.entities.*; import mindustry.entities.*;
@@ -460,24 +461,31 @@ public class PlacementFragment{
commandTable.add(Core.bundle.get("commandmode.name")).fill().center().labelAlign(Align.center).row(); 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.image().color(Pal.accent).growX().pad(20f).padTop(0f).padBottom(4f).row();
commandTable.table(u -> { 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(); u.left();
int[] curCount = {0}; int[] curCount = {0};
UnitCommand[] currentCommand = {null}; Bits usedCommands = new Bits(content.unitCommands().size);
var commands = new Seq<UnitCommand>(); var commands = new Seq<UnitCommand>();
UnitStance[] currentStance = {null}; Bits usedStances = new Bits(content.unitStances().size);
var stances = new Seq<UnitStance>(); var stances = new Seq<UnitStance>();
var stancesOut = new Seq<UnitStance>(); var stancesOut = new Seq<UnitStance>();
rebuildCommand = () -> { rebuildCommand = () -> {
u.clearChildren(); u.clearChildren();
var units = control.input.selectedUnits; var units = control.input.selectedUnits;
if(units.size > 0){ if(units.size > 0){
usedCommands.clear();
usedStances.clear();
commands.clear(); commands.clear();
stances.clear(); stances.clear();
boolean firstCommand = false, firstStance = false;
int[] counts = new int[content.units().size]; int[] counts = new int[content.units().size];
for(var unit : units){ for(var unit : units){
@@ -486,12 +494,11 @@ public class PlacementFragment{
stancesOut.clear(); stancesOut.clear();
unit.type.getUnitStances(unit, stancesOut); unit.type.getUnitStances(unit, stancesOut);
if(!firstStance){ for(var stance : stancesOut){
stances.add(stancesOut); if(!usedStances.get(stance.id)){
firstStance = true; stances.add(stance);
}else{ usedStances.set(stance.id);
//remove commands that this next unit type doesn't have }
stances.removeAll(st -> !stancesOut.contains(st));
} }
} }
@@ -529,12 +536,11 @@ public class PlacementFragment{
unitlist.row(); unitlist.row();
} }
if(!firstCommand){ for(var command : type.commands){
commands.add(type.commands); if(!usedCommands.get(command.id)){
firstCommand = true; commands.add(command);
}else{ usedCommands.set(command.id);
//remove commands that this next unit type doesn't have }
commands.removeAll(com -> !type.commands.contains(com));
} }
} }
} }
@@ -548,8 +554,8 @@ public class PlacementFragment{
int scol = 0; int scol = 0;
for(var command : commands){ for(var command : commands){
coms.button(Icon.icons.get(command.icon, Icon.cancel), Styles.clearNoneTogglei, () -> { coms.button(Icon.icons.get(command.icon, Icon.cancel), Styles.clearNoneTogglei, () -> {
Call.setUnitCommand(player, units.mapInt(un -> un.id).toArray(), command); Call.setUnitCommand(player, units.mapInt(un -> un.id, un -> un.type.allowCommand(un, command)).toArray(), command);
}).checked(i -> currentCommand[0] == command).size(50f).tooltip(command.localized(), true); }).checked(i -> activeCommands.get(command.id)).size(50f).tooltip(command.localized(), true);
if(++scol % 6 == 0) coms.row(); if(++scol % 6 == 0) coms.row();
} }
@@ -571,8 +577,8 @@ public class PlacementFragment{
for(var stance : stances){ for(var stance : stances){
coms.button(stance.getIcon(), Styles.clearNoneTogglei, () -> { coms.button(stance.getIcon(), Styles.clearNoneTogglei, () -> {
Call.setUnitStance(player, units.mapInt(un -> un.id).toArray(), stance); Call.setUnitStance(player, units.mapInt(un -> un.id, un -> un.type.allowStance(un, stance)).toArray(), stance);
}).checked(i -> currentStance[0] == stance).size(50f).tooltip(stance.localized(), true); }).checked(i -> activeStances.get(stance.id)).size(50f).tooltip(stance.localized(), true);
if(++scol % 6 == 0) coms.row(); if(++scol % 6 == 0) coms.row();
} }
@@ -585,58 +591,50 @@ public class PlacementFragment{
u.update(() -> { u.update(() -> {
{ {
boolean hadCommand = false, hadStance = false; activeCommands.clear();
UnitCommand shareCommand = null; activeStances.clear();
UnitStance shareStance = null; availableCommands.clear();
availableStances.clear();
//find the command that all units have, or null if they do not share one //find the command that all units have, or null if they do not share one
for(var unit : control.input.selectedUnits){ for(var unit : control.input.selectedUnits){
if(unit.isCommandable()){ if(unit.controller() instanceof CommandAI cmd){
var nextCommand = unit.command().command; activeCommands.set(cmd.command.id);
activeStances.set(cmd.stance.id);
if(hadCommand){ for(var command : unit.type.commands){
if(shareCommand != nextCommand){ availableCommands.set(command.id);
shareCommand = null;
}
}else{
shareCommand = nextCommand;
hadCommand = true;
} }
var nextStance = unit.command().stance; stancesOut.clear();
unit.type.getUnitStances(unit, stancesOut);
if(hadStance){ for(var stance : stancesOut){
if(shareStance != nextStance){ availableStances.set(stance.id);
shareStance = null;
}
}else{
shareStance = nextStance;
hadStance = true;
} }
} }
} }
int size = control.input.selectedUnits.size; 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; 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... //not a huge fan of running input logic here, but it's convenient as the stance arrays are all here...
for(UnitStance stance : stances){ for(UnitStance stance : stances){
//first stance must always be the stop stance //first stance must always be the stop stance
if(stance.keybind != null && Core.input.keyTap(stance.keybind)){ 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){ for(UnitCommand command : commands){
//first stance must always be the stop stance //first stance must always be the stop stance
if(command.keybind != null && Core.input.keyTap(command.keybind)){ 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);
} }
} }
} }

View File

@@ -26,4 +26,4 @@ org.gradle.caching=true
org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.socketTimeout=100000
org.gradle.internal.http.connectionTimeout=100000 org.gradle.internal.http.connectionTimeout=100000
android.enableR8.fullMode=false android.enableR8.fullMode=false
archash=f3b1dc4a13 archash=597a814beb