Fixed RTS AI targeting unreachable things
This commit is contained in:
@@ -164,6 +164,19 @@ public class ControlPathfinder{
|
||||
* @param pathId a unique ID for this location query, which should change every time the 'destination' vector is modified.
|
||||
* */
|
||||
public boolean getPathPosition(Unit unit, int pathId, Vec2 destination, Vec2 out){
|
||||
return getPathPosition(unit, pathId, destination, out, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether a path is ready.
|
||||
* @param pathId a unique ID for this location query, which should change every time the 'destination' vector is modified.
|
||||
* @param noResultFound extra return value for storing whether no valid path to the destination exists (thanks java!)
|
||||
* */
|
||||
public boolean getPathPosition(Unit unit, int pathId, Vec2 destination, Vec2 out, @Nullable boolean[] noResultFound){
|
||||
if(noResultFound != null){
|
||||
noResultFound[0] = false;
|
||||
}
|
||||
|
||||
//uninitialized
|
||||
if(threads == null || !world.tiles.in(World.toTile(destination.x), World.toTile(destination.y))) return false;
|
||||
|
||||
@@ -272,6 +285,10 @@ public class ControlPathfinder{
|
||||
out.set(unit);
|
||||
//end of path, we're done here? reset path? what???
|
||||
}
|
||||
|
||||
if(noResultFound != null){
|
||||
noResultFound[0] = !req.foundEnd;
|
||||
}
|
||||
}
|
||||
|
||||
return req.done;
|
||||
|
||||
@@ -7,6 +7,7 @@ import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ai.types.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -25,7 +26,7 @@ public class RtsAI{
|
||||
static final Seq<Building> targets = new Seq<>();
|
||||
static final Seq<Unit> squad = new Seq<>(false);
|
||||
static final IntSet used = new IntSet();
|
||||
static final IntSet assignedTargets = new IntSet();
|
||||
static final IntSet assignedTargets = new IntSet(), invalidTarget = new IntSet();
|
||||
static final float squadRadius = 140f;
|
||||
static final int timeUpdate = 0, timerSpawn = 1, maxTargetsChecked = 15;
|
||||
|
||||
@@ -233,6 +234,14 @@ public class RtsAI{
|
||||
|
||||
boolean anyDefend = defendPos != null || defendTarget != null;
|
||||
|
||||
invalidTarget.clear();
|
||||
|
||||
for(var unit : squad){
|
||||
if(unit.controller() instanceof CommandAI ai){
|
||||
invalidTarget.addAll(ai.unreachableBuildings);
|
||||
}
|
||||
}
|
||||
|
||||
var build = anyDefend ? null : findTarget(ax, ay, units.size, dps, health, units.first().flag == 0);
|
||||
|
||||
if(build != null || anyDefend){
|
||||
@@ -267,7 +276,7 @@ public class RtsAI{
|
||||
for(var flag : flags){
|
||||
targets.addAll(Vars.indexer.getEnemy(data.team, flag));
|
||||
}
|
||||
targets.removeAll(b -> assignedTargets.contains(b.id));
|
||||
targets.removeAll(b -> assignedTargets.contains(b.id) || invalidTarget.contains(b.pos()));
|
||||
|
||||
if(targets.size == 0) return null;
|
||||
|
||||
@@ -327,9 +336,9 @@ public class RtsAI{
|
||||
float timeDestroySelf = Mathf.zero(dp) ? Float.POSITIVE_INFINITY : selfHealth / dp;
|
||||
|
||||
//other can never be destroyed | other destroys self instantly
|
||||
if(Float.isInfinite(timeDestroyOther) | Mathf.zero(timeDestroySelf)) return 0f;
|
||||
if(Float.isInfinite(timeDestroyOther) || Mathf.zero(timeDestroySelf)) return 0f;
|
||||
//self can never be destroyed | self destroys other instantly
|
||||
if(Float.isInfinite(timeDestroySelf) | Mathf.zero(timeDestroyOther)) return 1f;
|
||||
if(Float.isInfinite(timeDestroySelf) || Mathf.zero(timeDestroyOther)) return 1f;
|
||||
|
||||
//examples:
|
||||
// self 10 sec / other 10 sec -> can destroy target with 100 % losses -> returns 1
|
||||
|
||||
@@ -14,9 +14,12 @@ import mindustry.world.*;
|
||||
public class CommandAI extends AIController{
|
||||
protected static final float localInterval = 40f;
|
||||
protected static final Vec2 vecOut = new Vec2(), flockVec = new Vec2(), separation = new Vec2(), cohesion = new Vec2(), massCenter = new Vec2();
|
||||
protected static final boolean[] noFound = {false};
|
||||
|
||||
public @Nullable Vec2 targetPos;
|
||||
public @Nullable Teamc attackTarget;
|
||||
/** All encountered unreachable buildings of this AI. Why a sequence? Because contains() is very rarely called on it. */
|
||||
public IntSeq unreachableBuildings = new IntSeq(8);
|
||||
|
||||
protected boolean stopAtTarget;
|
||||
protected Vec2 lastTargetPos;
|
||||
@@ -133,7 +136,17 @@ public class CommandAI extends AIController{
|
||||
vecOut.set(targetPos);
|
||||
|
||||
if(unit.isGrounded()){
|
||||
move = Vars.controlPath.getPathPosition(unit, pathId, targetPos, vecOut);
|
||||
move = Vars.controlPath.getPathPosition(unit, pathId, targetPos, vecOut, noFound);
|
||||
|
||||
//if the path is invalid, stop trying and record the end as unreachable
|
||||
if(unit.team.isAI() && noFound[0]){
|
||||
if(attackTarget instanceof Building build){
|
||||
unreachableBuildings.addUnique(build.pos());
|
||||
}
|
||||
attackTarget = null;
|
||||
targetPos = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float engageRange = unit.type.range - 10f;
|
||||
|
||||
Reference in New Issue
Block a user