Basic unit boost command support

This commit is contained in:
Anuken
2023-02-11 17:40:57 -05:00
parent 946e36c66e
commit ec8262418f
9 changed files with 81 additions and 21 deletions

View File

@@ -339,6 +339,7 @@ command.repair = Repair
command.rebuild = Rebuild command.rebuild = Rebuild
command.assist = Assist Player command.assist = Assist Player
command.move = Move command.move = Move
command.boost = Boost
openlink = Open Link openlink = Open Link
copylink = Copy Link copylink = Copy Link
back = Back back = Back

View File

@@ -14,7 +14,10 @@ public class UnitCommand{
public static final UnitCommand public static final UnitCommand
moveCommand = new UnitCommand("move", "right", u -> null), moveCommand = new UnitCommand("move", "right", u -> null){{
drawTarget = true;
resetTarget = false;
}},
repairCommand = new UnitCommand("repair", "modeSurvival", u -> new RepairAI()), repairCommand = new UnitCommand("repair", "modeSurvival", u -> new RepairAI()),
rebuildCommand = new UnitCommand("rebuild", "hammer", u -> new BuilderAI()), rebuildCommand = new UnitCommand("rebuild", "hammer", u -> new BuilderAI()),
assistCommand = new UnitCommand("assist", "players", u -> { assistCommand = new UnitCommand("assist", "players", u -> {
@@ -22,7 +25,12 @@ public class UnitCommand{
ai.onlyAssist = true; ai.onlyAssist = true;
return ai; return ai;
}), }),
mineCommand = new UnitCommand("mine", "production", u -> new MinerAI()); mineCommand = new UnitCommand("mine", "production", u -> new MinerAI()),
boostCommand = new UnitCommand("boost", "up", u -> new BoostAI()){{
switchToMove = false;
drawTarget = true;
resetTarget = false;
}};
/** Unique ID number. */ /** Unique ID number. */
public final int id; public final int id;
@@ -32,6 +40,12 @@ public class UnitCommand{
public final String icon; public final String icon;
/** Controller that this unit will use when this command is used. Return null for "default" behavior. */ /** Controller that this unit will use when this command is used. Return null for "default" behavior. */
public final Func<Unit, AIController> controller; public final Func<Unit, AIController> controller;
/** If true, this unit will automatically switch away to the move command when given a position. */
public boolean switchToMove = true;
/** Whether to draw the movement/attack target. */
public boolean drawTarget = false;
/** Whether to reset targets when switching to or from this command. */
public boolean resetTarget = true;
public UnitCommand(String name, String icon, Func<Unit, AIController> controller){ public UnitCommand(String name, String icon, Func<Unit, AIController> controller){
this.name = name; this.name = name;

View File

@@ -0,0 +1,21 @@
package mindustry.ai.types;
import mindustry.ai.*;
import mindustry.entities.units.*;
//not meant to be used outside RTS-AI-controlled units
public class BoostAI extends AIController{
@Override
public void updateUnit(){
if(unit.controller() instanceof CommandAI ai){
ai.defaultBehavior();
unit.updateBoosting(true);
//auto land when near target
if(ai.attackTarget != null && unit.within(ai.attackTarget, unit.range())){
unit.command().command(UnitCommand.moveCommand);
}
}
}
}

View File

@@ -35,8 +35,8 @@ public class CommandAI extends AIController{
/** Last command type assigned. Used for detecting command changes. */ /** Last command type assigned. Used for detecting command changes. */
protected @Nullable UnitCommand lastCommand; protected @Nullable UnitCommand lastCommand;
public @Nullable UnitCommand currentCommand(){ public UnitCommand currentCommand(){
return command; return command == null ? UnitCommand.moveCommand : command;
} }
/** Attempts to assign a command to this unit. If not supported by the unit type, does nothing. */ /** Attempts to assign a command to this unit. If not supported by the unit type, does nothing. */
@@ -62,7 +62,7 @@ public class CommandAI extends AIController{
} }
//update command controller based on index. //update command controller based on index.
var curCommand = currentCommand(); var curCommand = command;
if(lastCommand != curCommand){ if(lastCommand != curCommand){
lastCommand = curCommand; lastCommand = curCommand;
commandController = (curCommand == null ? null : curCommand.controller.get(unit)); commandController = (curCommand == null ? null : curCommand.controller.get(unit));
@@ -72,8 +72,14 @@ public class CommandAI extends AIController{
if(commandController != null){ if(commandController != null){
if(commandController.unit() != unit) commandController.unit(unit); if(commandController.unit() != unit) commandController.unit(unit);
commandController.updateUnit(); commandController.updateUnit();
return; }else{
defaultBehavior();
//boosting control is not supported, so just don't.
unit.updateBoosting(false);
} }
}
public void defaultBehavior(){
//acquiring naval targets isn't supported yet, so use the fallback dumb AI //acquiring naval targets isn't supported yet, so use the fallback dumb AI
if(unit.team.isAI() && unit.team.rules().rtsAi && unit.type.naval){ if(unit.team.isAI() && unit.team.rules().rtsAi && unit.type.naval){
@@ -207,9 +213,6 @@ public class CommandAI extends AIController{
}else if(target != null){ }else if(target != null){
faceTarget(); faceTarget();
} }
//boosting control is not supported, so just don't.
unit.updateBoosting(false);
} }
@Override @Override
@@ -249,8 +252,12 @@ public class CommandAI extends AIController{
lastTargetPos = targetPos; lastTargetPos = targetPos;
} }
@Override
public void commandPosition(Vec2 pos){ public void commandPosition(Vec2 pos){
commandPosition(pos, false); commandPosition(pos, false);
if(commandController != null){
commandController.commandPosition(pos);
}
} }
public void commandPosition(Vec2 pos, boolean stopWhenInRange){ public void commandPosition(Vec2 pos, boolean stopWhenInRange){
@@ -261,8 +268,12 @@ public class CommandAI extends AIController{
this.stopWhenInRange = stopWhenInRange; this.stopWhenInRange = stopWhenInRange;
} }
@Override
public void commandTarget(Teamc moveTo){ public void commandTarget(Teamc moveTo){
commandTarget(moveTo, false); commandTarget(moveTo, false);
if(commandController != null){
commandController.commandTarget(moveTo);
}
} }
public void commandTarget(Teamc moveTo, boolean stopAtTarget){ public void commandTarget(Teamc moveTo, boolean stopAtTarget){

View File

@@ -64,7 +64,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
public void updateBoosting(boolean boost){ public void updateBoosting(boolean boost){
if(!type.canBoost) return; if(!type.canBoost || dead) return;
elevation = Mathf.approachDelta(elevation, type.canBoost ? Mathf.num(boost || onSolid() || (isFlying() && !canLand())) : 0f, type.riseSpeed); elevation = Mathf.approachDelta(elevation, type.canBoost ? Mathf.num(boost || onSolid() || (isFlying() && !canLand())) : 0f, type.riseSpeed);
} }

View File

@@ -222,6 +222,10 @@ public class AIController implements UnitController{
return target(x, y, range, air, ground); return target(x, y, range, air, ground);
} }
public void commandTarget(Teamc moveTo){}
public void commandPosition(Vec2 pos){}
/** Called after this controller is assigned a unit. */ /** Called after this controller is assigned a unit. */
public void init(){ public void init(){

View File

@@ -231,10 +231,13 @@ 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){
//implicitly order it to move //implicitly order it to move
if(ai.command == null || ai.command.switchToMove){
ai.command(UnitCommand.moveCommand); ai.command(UnitCommand.moveCommand);
}
if(teamTarget != null && teamTarget.team() != player.team()){ if(teamTarget != null && teamTarget.team() != player.team()){
ai.commandTarget(teamTarget); ai.commandTarget(teamTarget);
}else if(posTarget != null){ }else if(posTarget != null){
ai.commandPosition(posTarget); ai.commandPosition(posTarget);
} }
@@ -269,10 +272,12 @@ 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){
boolean reset = command.resetTarget || ai.currentCommand().resetTarget;
ai.command(command); ai.command(command);
//reset targeting if(reset){
ai.targetPos = null; ai.targetPos = null;
ai.attackTarget = null; ai.attackTarget = null;
}
unit.lastCommanded = player.coloredName(); unit.lastCommanded = player.coloredName();
} }
} }
@@ -868,7 +873,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
for(Unit unit : selectedUnits){ for(Unit unit : selectedUnits){
CommandAI ai = unit.command(); CommandAI ai = unit.command();
//draw target line //draw target line
if(ai.targetPos != null && ai.command == UnitCommand.moveCommand){ if(ai.targetPos != null && ai.currentCommand().drawTarget){
Position lineDest = ai.attackTarget != null ? ai.attackTarget : ai.targetPos; Position lineDest = ai.attackTarget != null ? ai.attackTarget : ai.targetPos;
Drawf.limitLine(unit, lineDest, unit.hitSize / 2f, 3.5f); Drawf.limitLine(unit, lineDest, unit.hitSize / 2f, 3.5f);
@@ -880,7 +885,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Drawf.square(unit.x, unit.y, unit.hitSize / 1.4f + 1f); Drawf.square(unit.x, unit.y, unit.hitSize / 1.4f + 1f);
//TODO when to draw, when to not? //TODO when to draw, when to not?
if(ai.attackTarget != null && ai.command == UnitCommand.moveCommand){ if(ai.attackTarget != null && ai.currentCommand().drawTarget){
Drawf.target(ai.attackTarget.getX(), ai.attackTarget.getY(), 6f, Pal.remove); Drawf.target(ai.attackTarget.getX(), ai.attackTarget.getY(), 6f, Pal.remove);
} }
} }

View File

@@ -805,6 +805,10 @@ public class UnitType extends UnlockableContent{
cmds.add(UnitCommand.moveCommand); cmds.add(UnitCommand.moveCommand);
if(canBoost){
cmds.add(UnitCommand.boostCommand);
}
//healing, mining and building is only supported for flying units; pathfinding to ambiguously reachable locations is hard. //healing, mining and building is only supported for flying units; pathfinding to ambiguously reachable locations is hard.
if(flying){ if(flying){
if(canHeal){ if(canHeal){

View File

@@ -514,7 +514,7 @@ public class PlacementFragment{
//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.isCommandable()){
var nextCommand = unit.command().currentCommand(); var nextCommand = unit.command().command;
if(hadCommand){ if(hadCommand){
if(shareCommand != nextCommand){ if(shareCommand != nextCommand){