Command setting UI for unit factories

This commit is contained in:
Anuken
2024-10-11 21:46:56 -04:00
parent efb0034c04
commit d9d5c8733b
5 changed files with 106 additions and 13 deletions

View File

@@ -322,7 +322,7 @@ public class UnitTypes{
speed = 0.55f;
hitSize = 8f;
health = 120f;
buildSpeed = 0.35f;
buildSpeed = 0.3f;
armor = 1f;
abilities.add(new RepairFieldAbility(10f, 60f * 4, 60f));
@@ -1256,6 +1256,7 @@ public class UnitTypes{
controller = u -> new MinerAI();
defaultCommand = UnitCommand.mineCommand;
allowChangeCommands = false;
flying = true;
drag = 0.06f;

View File

@@ -300,6 +300,8 @@ public class UnitType extends UnlockableContent implements Senseable{
/** Flags to target based on priority. Null indicates that the closest target should be found. The closest enemy core is used as a fallback. */
public BlockFlag[] targetFlags = {null};
/** A value of false is used to hide command changing UI in unit factories. */
public boolean allowChangeCommands = true;
/** Commands available to this unit through RTS controls. An empty array means commands will be assigned based on unit capabilities in init(). */
public UnitCommand[] commands = {};
/** Command to assign to this unit upon creation. Null indicates the first command in the array. */
@@ -860,6 +862,10 @@ public class UnitType extends UnlockableContent implements Senseable{
commands = cmds.toArray();
}
if(defaultCommand == null && commands.length > 0){
defaultCommand = commands[0];
}
if(stances.length == 0){
if(canAttack){
Seq<UnitStance> seq = Seq.with(UnitStance.stop, UnitStance.shoot, UnitStance.holdFire, UnitStance.pursueTarget, UnitStance.patrol);

View File

@@ -1,5 +1,6 @@
package mindustry.world.blocks;
import arc.*;
import arc.func.*;
import arc.math.*;
import arc.scene.style.*;
@@ -93,6 +94,11 @@ public class ItemSelection{
ScrollPane pane = new ScrollPane(cont, Styles.smallPane);
pane.setScrollingDisabled(true, false);
pane.exited(() -> {
if(pane.hasScroll()){
Core.scene.setScrollFocus(null);
}
});
if(block != null){
pane.setScrollYForce(block.selectScroll);

View File

@@ -168,7 +168,7 @@ public class Reconstructor extends UnitBlock{
public boolean canSetCommand(){
var output = unit();
return output != null && output.commands.length > 1;
return output != null && output.commands.length > 1 && output.allowChangeCommands;
}
@Override

View File

@@ -6,11 +6,13 @@ import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
import mindustry.ai.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
@@ -46,23 +48,32 @@ public class UnitFactory extends UnitBlock{
commandable = true;
ambientSound = Sounds.respawning;
config(Integer.class, (UnitFactoryBuild tile, Integer i) -> {
config(Integer.class, (UnitFactoryBuild build, Integer i) -> {
if(!configurable) return;
if(tile.currentPlan == i) return;
tile.currentPlan = i < 0 || i >= plans.size ? -1 : i;
tile.progress = 0;
if(build.currentPlan == i) return;
build.currentPlan = i < 0 || i >= plans.size ? -1 : i;
build.progress = 0;
if(build.command != null && !Structs.contains(build.unit().commands, build.command)){
build.command = null;
}
});
config(UnitType.class, (UnitFactoryBuild tile, UnitType val) -> {
config(UnitType.class, (UnitFactoryBuild build, UnitType val) -> {
if(!configurable) return;
int next = plans.indexOf(p -> p.unit == val);
if(tile.currentPlan == next) return;
tile.currentPlan = next;
tile.progress = 0;
if(build.currentPlan == next) return;
build.currentPlan = next;
build.progress = 0;
if(build.command != null && !Structs.contains(val.commands, build.command)){
build.command = null;
}
});
config(UnitCommand.class, (UnitFactoryBuild build, UnitCommand command) -> build.command = command);
configClear((UnitFactoryBuild build) -> build.command = null);
consume(new ConsumeItemDynamic((UnitFactoryBuild e) -> e.currentPlan != -1 ? plans.get(Math.min(e.currentPlan, plans.size - 1)).requirements : ItemStack.empty));
}
@@ -177,12 +188,18 @@ public class UnitFactory extends UnitBlock{
public class UnitFactoryBuild extends UnitBuild{
public @Nullable Vec2 commandPos;
public @Nullable UnitCommand command;
public int currentPlan = -1;
public float fraction(){
return currentPlan == -1 ? 0 : progress / plans.get(currentPlan).time;
}
public boolean canSetCommand(){
var output = unit();
return output != null && output.commands.length > 1 && output.allowChangeCommands;
}
@Override
public void created(){
//auto-set to the first plan, it's better than nothing.
@@ -225,6 +242,59 @@ public class UnitFactory extends UnitBlock{
if(units.any()){
ItemSelection.buildTable(UnitFactory.this, table, units, () -> currentPlan == -1 ? null : plans.get(currentPlan).unit, unit -> configure(plans.indexOf(u -> u.unit == unit)), selectionRows, selectionColumns);
table.row();
Table commands = new Table();
commands.top().left();
commands.background(Styles.black6);
Runnable rebuildCommands = () -> {
commands.clear();
var unit = unit();
if(unit != null && canSetCommand()){
var group = new ButtonGroup<ImageButton>();
group.setMinCheckCount(0);
int i = 0, columns = Mathf.clamp(units.size, 2, selectionColumns);
var list = unit.commands;
commands.image(Tex.whiteui, Pal.gray).height(4f).growX().colspan(columns).row();
for(var item : list){
ImageButton button = commands.button(item.getIcon(), Styles.clearNoneTogglei, 40f, () -> {
configure(item);
}).tooltip(item.localized()).group(group).get();
button.update(() -> button.setChecked(command == item || (command == null && unit.defaultCommand == item)));
if(++i % columns == 0){
commands.row();
}
}
if(list.length < columns){
for(int j = 0; j < (columns - list.length); j++){
commands.add().size(40f);
}
}
}
};
rebuildCommands.run();
UnitType[] lastUnit = {unit()};
commands.update(() -> {
if(lastUnit[0] != unit()){
lastUnit[0] = unit();
rebuildCommands.run();
}
});
table.row();
table.add(commands).fillX().left();
}else{
table.table(Styles.black3, t -> t.add("@none").color(Color.lightGray));
}
@@ -311,9 +381,14 @@ public class UnitFactory extends UnitBlock{
progress %= 1f;
Unit unit = plan.unit.create(team);
if(commandPos != null && unit.isCommandable()){
unit.command().commandPosition(commandPos);
if(unit.isCommandable()){
if(commandPos != null){
unit.command().commandPosition(commandPos);
}
unit.command().command(command == null && payload.unit.type.defaultCommand != null ? payload.unit.type.defaultCommand : command);
}
payload = new UnitPayload(unit);
payVector.setZero();
consume();
@@ -349,7 +424,7 @@ public class UnitFactory extends UnitBlock{
@Override
public byte version(){
return 2;
return 3;
}
@Override
@@ -358,6 +433,7 @@ public class UnitFactory extends UnitBlock{
write.f(progress);
write.s(currentPlan);
TypeIO.writeVecNullable(write, commandPos);
TypeIO.writeCommand(write, command);
}
@Override
@@ -368,6 +444,10 @@ public class UnitFactory extends UnitBlock{
if(revision >= 2){
commandPos = TypeIO.readVecNullable(read);
}
if(revision >= 3){
command = TypeIO.readCommand(read);
}
}
}
}