Unit stances for specific item mining
This commit is contained in:
@@ -378,6 +378,8 @@ stance.holdfire = Stance: Hold Fire
|
|||||||
stance.pursuetarget = Stance: Pursue Target
|
stance.pursuetarget = Stance: Pursue Target
|
||||||
stance.patrol = Stance: Patrol Path
|
stance.patrol = Stance: Patrol Path
|
||||||
stance.ram = Stance: Ram\n[lightgray]Straight line movement, no pathfinding
|
stance.ram = Stance: Ram\n[lightgray]Straight line movement, no pathfinding
|
||||||
|
stance.mineauto = Automatic Mining
|
||||||
|
stance.mine = Mine Item: {0}
|
||||||
openlink = Open Link
|
openlink = Open Link
|
||||||
copylink = Copy Link
|
copylink = Copy Link
|
||||||
back = Back
|
back = Back
|
||||||
|
|||||||
33
core/src/mindustry/ai/ItemUnitStance.java
Normal file
33
core/src/mindustry/ai/ItemUnitStance.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package mindustry.ai;
|
||||||
|
|
||||||
|
import arc.*;
|
||||||
|
import arc.scene.style.*;
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import mindustry.type.*;
|
||||||
|
|
||||||
|
public class ItemUnitStance extends UnitStance{
|
||||||
|
private static ObjectMap<Item, ItemUnitStance> itemToStance = new ObjectMap<>();
|
||||||
|
|
||||||
|
public final Item item;
|
||||||
|
|
||||||
|
public ItemUnitStance(Item item){
|
||||||
|
super("item-" + item.name, "item-" + item.name, null);
|
||||||
|
this.item = item;
|
||||||
|
itemToStance.put(item, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable ItemUnitStance getByItem(Item item){
|
||||||
|
return itemToStance.get(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String localized(){
|
||||||
|
return Core.bundle.format("stance.mine", item.localizedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextureRegionDrawable getIcon(){
|
||||||
|
return new TextureRegionDrawable(item.uiIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,8 @@ public class UnitCommand extends MappableContent{
|
|||||||
public boolean resetTarget = true;
|
public boolean resetTarget = true;
|
||||||
/** */
|
/** */
|
||||||
public boolean exactArrival = false;
|
public boolean exactArrival = false;
|
||||||
|
/** If true, this command refreshes the list of stances when selected TODO: do not use, this will likely be removed later!*/
|
||||||
|
public boolean refreshOnSelect = false;
|
||||||
/** Key to press for this command. */
|
/** Key to press for this command. */
|
||||||
public @Nullable Binding keybind = null;
|
public @Nullable Binding keybind = null;
|
||||||
|
|
||||||
@@ -76,7 +78,9 @@ public class UnitCommand extends MappableContent{
|
|||||||
ai.onlyAssist = true;
|
ai.onlyAssist = true;
|
||||||
return ai;
|
return ai;
|
||||||
});
|
});
|
||||||
mineCommand = new UnitCommand("mine", "production", Binding.unit_command_mine, u -> new MinerAI());
|
mineCommand = new UnitCommand("mine", "production", Binding.unit_command_mine, u -> new MinerAI()){{
|
||||||
|
refreshOnSelect = true;
|
||||||
|
}};
|
||||||
boostCommand = new UnitCommand("boost", "up", Binding.unit_command_boost, u -> new BoostAI()){{
|
boostCommand = new UnitCommand("boost", "up", Binding.unit_command_boost, u -> new BoostAI()){{
|
||||||
switchToMove = false;
|
switchToMove = false;
|
||||||
drawTarget = true;
|
drawTarget = true;
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package mindustry.ai;
|
|||||||
import arc.*;
|
import arc.*;
|
||||||
import arc.scene.style.*;
|
import arc.scene.style.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
import mindustry.*;
|
||||||
import mindustry.ctype.*;
|
import mindustry.ctype.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.input.*;
|
import mindustry.input.*;
|
||||||
|
import mindustry.type.*;
|
||||||
|
|
||||||
public class UnitStance extends MappableContent{
|
public class UnitStance extends MappableContent{
|
||||||
public static UnitStance stop, shoot, holdFire, pursueTarget, patrol, ram;
|
public static UnitStance stop, shoot, holdFire, pursueTarget, patrol, ram, mineAuto;
|
||||||
|
|
||||||
/** Name of UI icon (from Icon class). */
|
/** Name of UI icon (from Icon class). */
|
||||||
public String icon;
|
public String icon;
|
||||||
@@ -30,7 +32,7 @@ public class UnitStance extends MappableContent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public char getEmoji() {
|
public char getEmoji() {
|
||||||
return (char) Iconc.codes.get(icon, Iconc.cancel);
|
return (char)Iconc.codes.get(icon, Iconc.cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -50,5 +52,11 @@ public class UnitStance extends MappableContent{
|
|||||||
pursueTarget = new UnitStance("pursuetarget", "right", Binding.unit_stance_pursue_target);
|
pursueTarget = new UnitStance("pursuetarget", "right", Binding.unit_stance_pursue_target);
|
||||||
patrol = new UnitStance("patrol", "refresh", Binding.unit_stance_patrol);
|
patrol = new UnitStance("patrol", "refresh", Binding.unit_stance_patrol);
|
||||||
ram = new UnitStance("ram", "rightOpen", Binding.unit_stance_ram);
|
ram = new UnitStance("ram", "rightOpen", Binding.unit_stance_ram);
|
||||||
|
mineAuto = new UnitStance("mineauto", "settings", null);
|
||||||
|
|
||||||
|
//Only vanilla items are supported for now
|
||||||
|
for(Item item : Vars.content.items()){
|
||||||
|
new ItemUnitStance(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ public class CommandAI extends AIController{
|
|||||||
//this should not be possible
|
//this should not be possible
|
||||||
if(stance == UnitStance.stop) stance = UnitStance.shoot;
|
if(stance == UnitStance.stop) stance = UnitStance.shoot;
|
||||||
|
|
||||||
|
//fix incorrect stance when mining
|
||||||
|
if(command == UnitCommand.mineCommand && stance != UnitStance.mineAuto && !(stance instanceof ItemUnitStance)){
|
||||||
|
stance = UnitStance.mineAuto;
|
||||||
|
}
|
||||||
|
|
||||||
//pursue the target if relevant
|
//pursue the target if relevant
|
||||||
if(stance == UnitStance.pursueTarget && target != null && attackTarget == null && targetPos == null){
|
if(stance == UnitStance.pursueTarget && target != null && attackTarget == null && targetPos == null){
|
||||||
commandTarget(target, false);
|
commandTarget(target, false);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package mindustry.ai.types;
|
package mindustry.ai.types;
|
||||||
|
|
||||||
|
import mindustry.ai.*;
|
||||||
import mindustry.entities.units.*;
|
import mindustry.entities.units.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
@@ -22,8 +23,12 @@ public class MinerAI extends AIController{
|
|||||||
unit.mineTile(null);
|
unit.mineTile(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item autoItem = unit.controller() instanceof CommandAI ai && ai.stance instanceof ItemUnitStance stance ? stance.item : null;
|
||||||
|
|
||||||
if(mining){
|
if(mining){
|
||||||
if(timer.get(timerTarget2, 60 * 4) || targetItem == null){
|
if(autoItem != null){
|
||||||
|
targetItem = autoItem;
|
||||||
|
}else if(timer.get(timerTarget2, 60 * 4) || targetItem == null){
|
||||||
targetItem = unit.type.mineItems.min(i -> indexer.hasOre(i) && unit.canMine(i), i -> core.items.get(i));
|
targetItem = unit.type.mineItems.min(i -> indexer.hasOre(i) && unit.canMine(i), i -> core.items.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1256,11 +1256,7 @@ public class UnitTypes{
|
|||||||
//region air support
|
//region air support
|
||||||
|
|
||||||
mono = new UnitType("mono"){{
|
mono = new UnitType("mono"){{
|
||||||
//there's no reason to command monos anywhere. it's just annoying.
|
|
||||||
controller = u -> new MinerAI();
|
|
||||||
|
|
||||||
defaultCommand = UnitCommand.mineCommand;
|
defaultCommand = UnitCommand.mineCommand;
|
||||||
allowChangeCommands = false;
|
|
||||||
|
|
||||||
flying = true;
|
flying = true;
|
||||||
drag = 0.06f;
|
drag = 0.06f;
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ public class ContentLoader{
|
|||||||
/** Creates all base types. */
|
/** Creates all base types. */
|
||||||
public void createBaseContent(){
|
public void createBaseContent(){
|
||||||
UnitCommand.loadAll();
|
UnitCommand.loadAll();
|
||||||
UnitStance.loadAll();
|
|
||||||
TeamEntries.load();
|
TeamEntries.load();
|
||||||
Items.load();
|
Items.load();
|
||||||
|
UnitStance.loadAll(); //needs to access items
|
||||||
StatusEffects.load();
|
StatusEffects.load();
|
||||||
Liquids.load();
|
Liquids.load();
|
||||||
Bullets.load();
|
Bullets.load();
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
/** Used for dropping items. */
|
/** Used for dropping items. */
|
||||||
final static float playerSelectRange = mobile ? 17f : 11f;
|
final static float playerSelectRange = mobile ? 17f : 11f;
|
||||||
final static float unitSelectRadScl = 1f;
|
final static float unitSelectRadScl = 1f;
|
||||||
|
final static Seq<UnitStance> stancesOut = new Seq<>();
|
||||||
final static IntSeq removed = new IntSeq();
|
final static IntSeq removed = new IntSeq();
|
||||||
final static IntSet intSet = new IntSet();
|
final static IntSet intSet = new IntSet();
|
||||||
/** Maximum line length. */
|
/** Maximum line length. */
|
||||||
@@ -369,6 +370,13 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
ai.attackTarget = null;
|
ai.attackTarget = null;
|
||||||
}
|
}
|
||||||
unit.lastCommanded = player.coloredName();
|
unit.lastCommanded = player.coloredName();
|
||||||
|
|
||||||
|
//make sure its stance is valid
|
||||||
|
stancesOut.clear();
|
||||||
|
unit.type.getUnitStances(unit, stancesOut);
|
||||||
|
if(stancesOut.size > 0 && !stancesOut.contains(ai.stance)){
|
||||||
|
ai.stance = stancesOut.first();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -592,6 +592,24 @@ public class UnitType extends UnlockableContent implements Senseable{
|
|||||||
return hittable || (vulnerableWithPayloads && unit instanceof Payloadc p && p.hasPayload());
|
return hittable || (vulnerableWithPayloads && unit instanceof Payloadc p && p.hasPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Adds all available unit stances based on the unit's current state. This can change based on the command of the unit. */
|
||||||
|
public void getUnitStances(Unit unit, Seq<UnitStance> out){
|
||||||
|
//return mining stances based on present items
|
||||||
|
if(unit.controller() instanceof CommandAI ai && ai.currentCommand() == UnitCommand.mineCommand){
|
||||||
|
out.add(UnitStance.mineAuto);
|
||||||
|
for(Item item : indexer.getAllPresentOres()){
|
||||||
|
if(unit.canMine(item)){
|
||||||
|
var itemStance = ItemUnitStance.getByItem(item);
|
||||||
|
if(itemStance != null){
|
||||||
|
out.add(itemStance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
out.addAll(stances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void update(Unit unit){
|
public void update(Unit unit){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,17 +468,33 @@ public class PlacementFragment{
|
|||||||
UnitStance[] currentStance = {null};
|
UnitStance[] currentStance = {null};
|
||||||
var stances = new Seq<UnitStance>();
|
var stances = 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){
|
||||||
int[] counts = new int[content.units().size];
|
|
||||||
for(var unit : units){
|
|
||||||
counts[unit.type.id] ++;
|
|
||||||
}
|
|
||||||
commands.clear();
|
commands.clear();
|
||||||
stances.clear();
|
stances.clear();
|
||||||
|
|
||||||
boolean firstCommand = false, firstStance = false;
|
boolean firstCommand = false, firstStance = false;
|
||||||
|
int[] counts = new int[content.units().size];
|
||||||
|
|
||||||
|
for(var unit : units){
|
||||||
|
counts[unit.type.id] ++;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Table unitlist = u.table().growX().left().get();
|
Table unitlist = u.table().growX().left().get();
|
||||||
unitlist.left();
|
unitlist.left();
|
||||||
|
|
||||||
@@ -520,14 +536,6 @@ public class PlacementFragment{
|
|||||||
//remove commands that this next unit type doesn't have
|
//remove commands that this next unit type doesn't have
|
||||||
commands.removeAll(com -> !type.commands.contains(com));
|
commands.removeAll(com -> !type.commands.contains(com));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!firstStance){
|
|
||||||
stances.add(type.stances);
|
|
||||||
firstStance = true;
|
|
||||||
}else{
|
|
||||||
//remove commands that this next unit type doesn't have
|
|
||||||
stances.removeAll(st -> !type.stances.contains(st));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +570,7 @@ public class PlacementFragment{
|
|||||||
int scol = 0;
|
int scol = 0;
|
||||||
for(var stance : stances){
|
for(var stance : stances){
|
||||||
|
|
||||||
coms.button(Icon.icons.get(stance.icon, Icon.cancel), 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).toArray(), stance);
|
||||||
}).checked(i -> currentStance[0] == stance).size(50f).tooltip(stance.localized(), true);
|
}).checked(i -> currentStance[0] == stance).size(50f).tooltip(stance.localized(), true);
|
||||||
|
|
||||||
@@ -608,15 +616,15 @@ public class PlacementFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCommand[0] = shareCommand;
|
|
||||||
currentStance[0] = shareStance;
|
|
||||||
|
|
||||||
int size = control.input.selectedUnits.size;
|
int size = control.input.selectedUnits.size;
|
||||||
if(curCount[0] != size){
|
if(curCount[0] != size || (currentCommand[0] != shareCommand && currentCommand[0] != null && (currentCommand[0].refreshOnSelect || shareCommand.refreshOnSelect))){
|
||||||
curCount[0] = size;
|
curCount[0] = size;
|
||||||
rebuildCommand.run();
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user