Simple enemy rebuilding AI + fleeing
This commit is contained in:
@@ -57,9 +57,9 @@ public class BaseAI{
|
||||
wallType = BaseGenerator.getDifficultyWall(1, data.team.rules().aiTier / 0.8f);
|
||||
}
|
||||
|
||||
if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 2.5f) && data.hasCore()){
|
||||
if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 6f) && data.hasCore()){
|
||||
CoreBlock block = (CoreBlock)data.core().block;
|
||||
int coreUnits = Groups.unit.count(u -> u.team == data.team && u.type == block.unitType);
|
||||
int coreUnits = data.countType(block.unitType);
|
||||
|
||||
//create AI core unit(s)
|
||||
if(!state.isEditor() && coreUnits < data.cores.size){
|
||||
|
||||
@@ -11,6 +11,7 @@ import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
@@ -38,9 +39,6 @@ public class BlockIndexer{
|
||||
private Seq<Building>[][] flagMap = new Seq[Team.all.length][BlockFlag.all.length];
|
||||
/** Counts whether a certain floor is present in the world upon load. */
|
||||
private boolean[] blocksPresent;
|
||||
|
||||
/** Array used for returning and reusing. */
|
||||
private Seq<Tile> returnArray = new Seq<>();
|
||||
/** Array used for returning and reusing. */
|
||||
private Seq<Building> breturnArray = new Seq<>(Building.class);
|
||||
|
||||
@@ -114,6 +112,11 @@ public class BlockIndexer{
|
||||
data.buildings.remove(build);
|
||||
}
|
||||
|
||||
//remove indexed turret
|
||||
if(data.turrets != null && build.block.attacks){
|
||||
data.turrets.remove(build);
|
||||
}
|
||||
|
||||
//is no longer registered
|
||||
build.wasDamaged = false;
|
||||
|
||||
@@ -442,6 +445,14 @@ public class BlockIndexer{
|
||||
}
|
||||
data.buildings.insert(tile.build);
|
||||
|
||||
if(tile.block().attacks && tile.build instanceof Ranged){
|
||||
if(data.turrets == null){
|
||||
data.turrets = new TurretQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
}
|
||||
|
||||
data.turrets.insert(tile.build);
|
||||
}
|
||||
|
||||
notifyBuildDamaged(tile.build);
|
||||
}
|
||||
|
||||
@@ -452,4 +463,21 @@ public class BlockIndexer{
|
||||
//bounds checks only needed in very specific scenarios
|
||||
if(tile.blockID() < blocksPresent.length) blocksPresent[tile.blockID()] = true;
|
||||
}
|
||||
|
||||
static class TurretQuadtree extends QuadTree<Building>{
|
||||
|
||||
public TurretQuadtree(Rect bounds){
|
||||
super(bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitbox(Building build){
|
||||
tmp.setCentered(build.x, build.y, ((Ranged)build).range() * 2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QuadTree<Building> newChild(Rect rect){
|
||||
return new TurretQuadtree(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.Teams.*;
|
||||
@@ -15,6 +16,7 @@ import mindustry.graphics.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.defense.turrets.Turret.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
@@ -24,7 +26,7 @@ public class RtsAI{
|
||||
static final IntSet used = new IntSet();
|
||||
static final IntSet assignedTargets = new IntSet();
|
||||
static final float squadRadius = 120f;
|
||||
static final int timeUpdate = 0;
|
||||
static final int timeUpdate = 0, timerSpawn = 1;
|
||||
static final float minWeight = 0.9f;
|
||||
|
||||
//in order of priority??
|
||||
@@ -32,7 +34,7 @@ public class RtsAI{
|
||||
static final ObjectFloatMap<Building> weights = new ObjectFloatMap<>();
|
||||
static final int minSquadSize = 4;
|
||||
//TODO max squad size
|
||||
static final boolean debug = true;
|
||||
static final boolean debug = OS.hasProp("mindustry.debug");
|
||||
|
||||
final Interval timer = new Interval(10);
|
||||
final TeamData data;
|
||||
@@ -77,6 +79,22 @@ public class RtsAI{
|
||||
public void update(){
|
||||
if(timer.get(timeUpdate, 60f * 2f)){
|
||||
assignSquads();
|
||||
checkBuilding();
|
||||
}
|
||||
}
|
||||
|
||||
void checkBuilding(){
|
||||
if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 7f) && data.hasCore()){
|
||||
CoreBlock block = (CoreBlock)data.core().block;
|
||||
int coreUnits = data.countType(block.unitType);
|
||||
|
||||
//create AI core unit(s) at random cores
|
||||
if(coreUnits < data.cores.size){
|
||||
Unit unit = block.unitType.create(data.team);
|
||||
unit.set(data.cores.random());
|
||||
unit.add();
|
||||
Fx.spawn.at(unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,15 +13,26 @@ import mindustry.world.blocks.ConstructBlock.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BuilderAI extends AIController{
|
||||
public static float buildRadius = 1500, retreatDst = 110f, fleeRange = 370f, retreatDelay = Time.toSeconds * 2f;
|
||||
public static float buildRadius = 1500, retreatDst = 110f, retreatDelay = Time.toSeconds * 2f;
|
||||
|
||||
public @Nullable Unit following;
|
||||
public @Nullable Teamc enemy;
|
||||
public @Nullable BlockPlan lastPlan;
|
||||
|
||||
public float fleeRange = 370f;
|
||||
public boolean alwaysFlee;
|
||||
|
||||
boolean found = false;
|
||||
float retreatTimer;
|
||||
|
||||
public BuilderAI(boolean alwaysFlee, float fleeRange){
|
||||
this.alwaysFlee = alwaysFlee;
|
||||
this.fleeRange = fleeRange;
|
||||
}
|
||||
|
||||
public BuilderAI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMovement(){
|
||||
|
||||
@@ -46,15 +57,16 @@ public class BuilderAI extends AIController{
|
||||
unit.plans.clear();
|
||||
unit.plans.addFirst(following.buildPlan());
|
||||
lastPlan = null;
|
||||
}else if(unit.buildPlan() == null){
|
||||
}else if(unit.buildPlan() == null || alwaysFlee){
|
||||
//not following anyone or building
|
||||
if(timer.get(timerTarget4, 40)){
|
||||
enemy = target(unit.x, unit.y, fleeRange, true, true);
|
||||
}
|
||||
|
||||
//fly away from enemy when not doing anything, but only after a delay
|
||||
if((retreatTimer += Time.delta) >= retreatDelay){
|
||||
if((retreatTimer += Time.delta) >= retreatDelay || alwaysFlee){
|
||||
if(enemy != null){
|
||||
unit.clearBuilding();
|
||||
var core = unit.closestCore();
|
||||
if(core != null && !unit.within(core, retreatDst)){
|
||||
moveTo(core, retreatDst);
|
||||
@@ -64,7 +76,7 @@ public class BuilderAI extends AIController{
|
||||
}
|
||||
|
||||
if(unit.buildPlan() != null){
|
||||
retreatTimer = 0f;
|
||||
if(!alwaysFlee) retreatTimer = 0f;
|
||||
//approach request if building
|
||||
BuildPlan req = unit.buildPlan();
|
||||
|
||||
@@ -131,7 +143,7 @@ public class BuilderAI extends AIController{
|
||||
//check if it's already been placed
|
||||
if(world.tile(block.x, block.y) != null && world.tile(block.x, block.y).block().id == block.block){
|
||||
blocks.removeFirst();
|
||||
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid
|
||||
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation) && (!alwaysFlee || !nearEnemy(block.x, block.y))){ //it's valid
|
||||
lastPlan = block;
|
||||
//add build request
|
||||
unit.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config));
|
||||
@@ -145,6 +157,10 @@ public class BuilderAI extends AIController{
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean nearEnemy(int x, int y){
|
||||
return Units.nearEnemy(unit.team, x * tilesize - fleeRange/2f, y * tilesize - fleeRange/2f, fleeRange, fleeRange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AIController fallback(){
|
||||
return unit.type.flying ? new FlyingAI() : new GroundAI();
|
||||
@@ -152,7 +168,7 @@ public class BuilderAI extends AIController{
|
||||
|
||||
@Override
|
||||
public boolean useFallback(){
|
||||
return state.rules.waves && unit.team == state.rules.waveTeam && !unit.team.rules().ai;
|
||||
return state.rules.waves && unit.team == state.rules.waveTeam && !unit.team.rules().ai && !unit.team.rules().rtsAi;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user