Setup for RTS AI

This commit is contained in:
Anuken
2022-02-17 18:06:33 -05:00
parent 9f3af412f0
commit aaba579314
12 changed files with 61 additions and 30 deletions

View File

@@ -1052,6 +1052,7 @@ rules.wavetimer = Wave Timer
rules.waves = Waves rules.waves = Waves
rules.attack = Attack Mode rules.attack = Attack Mode
rules.buildai = AI Building rules.buildai = AI Building
rules.rtsai = RTS AI
rules.aitier = AI Tier rules.aitier = AI Tier
rules.cleanupdeadteams = Clean Up Defeated Team Buildings (PvP) rules.cleanupdeadteams = Clean Up Defeated Team Buildings (PvP)
rules.corecapture = Capture Core On Destruction rules.corecapture = Capture Core On Destruction

View File

@@ -36,8 +36,8 @@ public class BaseAI{
private int lastX, lastY, lastW, lastH; private int lastX, lastY, lastW, lastH;
private boolean triedWalls, foundPath; private boolean triedWalls, foundPath;
TeamData data; final TeamData data;
Interval timer = new Interval(4); final Interval timer = new Interval(4);
IntSet path = new IntSet(); IntSet path = new IntSet();
IntSet calcPath = new IntSet(); IntSet calcPath = new IntSet();

View File

@@ -0,0 +1,15 @@
package mindustry.ai;
import mindustry.game.Teams.*;
public class RtsAI{
final TeamData data;
public RtsAI(TeamData data){
this.data = data;
}
public void update(){
}
}

View File

@@ -583,7 +583,7 @@ public class UnitTypes{
//region ground legs //region ground legs
crawler = new UnitType("crawler"){{ crawler = new UnitType("crawler"){{
defaultController = SuicideAI::new; aiController = SuicideAI::new;
speed = 1f; speed = 1f;
hitSize = 8f; hitSize = 8f;
@@ -1236,7 +1236,7 @@ public class UnitTypes{
//region air support //region air support
mono = new UnitType("mono"){{ mono = new UnitType("mono"){{
unitBasedDefaultController = u -> new MinerAI(); defaultController = u -> new MinerAI();
flying = true; flying = true;
drag = 0.06f; drag = 0.06f;
@@ -1255,7 +1255,7 @@ public class UnitTypes{
}}; }};
poly = new UnitType("poly"){{ poly = new UnitType("poly"){{
unitBasedDefaultController = u -> new BuilderAI(); defaultController = u -> new BuilderAI();
flying = true; flying = true;
drag = 0.05f; drag = 0.05f;
@@ -1311,7 +1311,7 @@ public class UnitTypes{
mega = new UnitType("mega"){{ mega = new UnitType("mega"){{
//TODO control? //TODO control?
defaultController = RepairAI::new; aiController = RepairAI::new;
mineTier = 3; mineTier = 3;
mineSpeed = 4f; mineSpeed = 4f;
@@ -1435,7 +1435,7 @@ public class UnitTypes{
}}; }};
oct = new UnitType("oct"){{ oct = new UnitType("oct"){{
defaultController = DefenderAI::new; aiController = DefenderAI::new;
armor = 16f; armor = 16f;
health = 24000; health = 24000;
@@ -2301,7 +2301,7 @@ public class UnitTypes{
//region core //region core
alpha = new UnitType("alpha"){{ alpha = new UnitType("alpha"){{
defaultController = BuilderAI::new; aiController = BuilderAI::new;
isCounted = false; isCounted = false;
lowAltitude = true; lowAltitude = true;
@@ -2338,7 +2338,7 @@ public class UnitTypes{
}}; }};
beta = new UnitType("beta"){{ beta = new UnitType("beta"){{
defaultController = BuilderAI::new; aiController = BuilderAI::new;
isCounted = false; isCounted = false;
flying = true; flying = true;
@@ -2379,7 +2379,7 @@ public class UnitTypes{
}}; }};
gamma = new UnitType("gamma"){{ gamma = new UnitType("gamma"){{
defaultController = BuilderAI::new; aiController = BuilderAI::new;
isCounted = false; isCounted = false;
lowAltitude = true; lowAltitude = true;
@@ -2922,7 +2922,7 @@ public class UnitTypes{
//region erekir - flying //region erekir - flying
quell = new ErekirUnitType("quell"){{ quell = new ErekirUnitType("quell"){{
defaultController = FlyingFollowAI::new; aiController = FlyingFollowAI::new;
envDisabled = 0; envDisabled = 0;
lowAltitude = false; lowAltitude = false;
@@ -2988,7 +2988,7 @@ public class UnitTypes{
}}; }};
disrupt = new ErekirUnitType("disrupt"){{ disrupt = new ErekirUnitType("disrupt"){{
defaultController = FlyingFollowAI::new; aiController = FlyingFollowAI::new;
envDisabled = 0; envDisabled = 0;
lowAltitude = false; lowAltitude = false;
@@ -3157,7 +3157,7 @@ public class UnitTypes{
//TODO bad name //TODO bad name
evoke = new ErekirUnitType("evoke"){{ evoke = new ErekirUnitType("evoke"){{
coreUnitDock = true; coreUnitDock = true;
defaultController = BuilderAI::new; aiController = BuilderAI::new;
isCounted = false; isCounted = false;
envDisabled = 0; envDisabled = 0;
@@ -3214,7 +3214,7 @@ public class UnitTypes{
incite = new ErekirUnitType("incite"){{ incite = new ErekirUnitType("incite"){{
coreUnitDock = true; coreUnitDock = true;
defaultController = BuilderAI::new; aiController = BuilderAI::new;
isCounted = false; isCounted = false;
envDisabled = 0; envDisabled = 0;
@@ -3283,7 +3283,7 @@ public class UnitTypes{
emanate = new ErekirUnitType("emanate"){{ emanate = new ErekirUnitType("emanate"){{
coreUnitDock = true; coreUnitDock = true;
defaultController = BuilderAI::new; aiController = BuilderAI::new;
isCounted = false; isCounted = false;
envDisabled = 0; envDisabled = 0;
@@ -3355,7 +3355,7 @@ public class UnitTypes{
}}; }};
manifold = new ErekirUnitType("manifold"){{ manifold = new ErekirUnitType("manifold"){{
defaultController = CargoAI::new; aiController = CargoAI::new;
isCounted = false; isCounted = false;
allowedInPayloads = false; allowedInPayloads = false;
logicControllable = false; logicControllable = false;
@@ -3382,7 +3382,7 @@ public class UnitTypes{
}}; }};
assemblyDrone = new ErekirUnitType("assembly-drone"){{ assemblyDrone = new ErekirUnitType("assembly-drone"){{
defaultController = AssemblerAI::new; aiController = AssemblerAI::new;
flying = true; flying = true;
drag = 0.06f; drag = 0.06f;

View File

@@ -3,6 +3,7 @@ package mindustry.core;
import arc.*; import arc.*;
import arc.math.*; import arc.math.*;
import arc.util.*; import arc.util.*;
import mindustry.ai.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.core.GameState.*; import mindustry.core.GameState.*;
import mindustry.ctype.*; import mindustry.ctype.*;
@@ -415,7 +416,13 @@ public class Logic implements ApplicationListener{
for(TeamData data : state.teams.getActive()){ for(TeamData data : state.teams.getActive()){
if(data.hasAI()){ if(data.hasAI()){
data.ai.update(); if(data.baseAi == null) data.baseAi = new BaseAI(data);
data.baseAi.update();
}
if(data.team.rules().rtsAi){
if(data.rtsAi == null) data.rtsAi = new RtsAI(data);
data.rtsAi.update();
} }
} }
} }

View File

@@ -201,7 +201,7 @@ public class Rules{
/** A team-specific ruleset. */ /** A team-specific ruleset. */
public static class TeamRule{ public static class TeamRule{
/** Whether to use building AI. */ /** Whether to use building AI. TODO remove, it is terrible. */
public boolean ai; public boolean ai;
/** TODO Tier of blocks/designs that the AI uses for building. [0, 1] */ /** TODO Tier of blocks/designs that the AI uses for building. [0, 1] */
public float aiTier = 1f; public float aiTier = 1f;
@@ -214,6 +214,9 @@ public class Rules{
/** If true, this team has infinite unit ammo. */ /** If true, this team has infinite unit ammo. */
public boolean infiniteAmmo; public boolean infiniteAmmo;
/** Enables "RTS" unit AI. TODO wip */
public boolean rtsAi;
/** How fast unit factories build units. */ /** How fast unit factories build units. */
public float unitBuildSpeedMultiplier = 1f; public float unitBuildSpeedMultiplier = 1f;
/** How much damage any other units deal. */ /** How much damage any other units deal. */

View File

@@ -222,7 +222,11 @@ public class Teams{
public static class TeamData{ public static class TeamData{
public final Seq<CoreBuild> cores = new Seq<>(); public final Seq<CoreBuild> cores = new Seq<>();
public final Team team; public final Team team;
public final BaseAI ai;
/** Handles building ""bases"". */
public @Nullable BaseAI baseAi;
/** Handles RTS unit control. */
public @Nullable RtsAI rtsAi;
private boolean presentFlag; private boolean presentFlag;
@@ -248,7 +252,6 @@ public class Teams{
public TeamData(Team team){ public TeamData(Team team){
this.team = team; this.team = team;
this.ai = new BaseAI(this);
} }
/** Destroys this team's presence on the map, killing part of its buildings and converting everything to 'derelict'. */ /** Destroys this team's presence on the map, killing part of its buildings and converting everything to 'derelict'. */

View File

@@ -454,13 +454,13 @@ public class ContentParser{
} }
if(value.has("controller")){ if(value.has("controller")){
unit.defaultController = supply(resolve(value.getString("controller"), FlyingAI.class)); unit.aiController = supply(resolve(value.getString("controller"), FlyingAI.class));
value.remove("controller"); value.remove("controller");
} }
if(value.has("unitBasedController")){ if(value.has("defaultController")){
unit.unitBasedDefaultController = u -> supply(resolve(value.getString("unitBasedController"), FlyingAI.class)).get(); unit.defaultController = u -> supply(resolve(value.getString("defaultController"), FlyingAI.class)).get();
value.remove("unitBasedController"); value.remove("defaultController");
} }
//read extra default waves //read extra default waves

View File

@@ -114,10 +114,10 @@ public class UnitType extends UnlockableContent{
//TODO different names for these fields. //TODO different names for these fields.
/** The default AI controller to assign on creation. */ /** The default AI controller to assign on creation. */
public Prov<? extends UnitController> defaultController = () -> !flying ? new GroundAI() : new FlyingAI(); public Prov<? extends UnitController> aiController = () -> !flying ? new GroundAI() : new FlyingAI();
/** Function that chooses AI controller based on unit entity. */ /** Function that chooses AI controller based on unit entity. */
//TODO -name is too long //TODO -name is too long
public Func<Unit, ? extends UnitController> unitBasedDefaultController = u -> !playerControllable || u.team.isAI() ? defaultController.get() : new CommandAI(); public Func<Unit, ? extends UnitController> defaultController = u -> !playerControllable || (u.team.isAI() && !u.team.rules().rtsAi) ? aiController.get() : new CommandAI();
public Color outlineColor = Pal.darkerMetal; public Color outlineColor = Pal.darkerMetal;
public int outlineRadius = 3; public int outlineRadius = 3;
@@ -218,7 +218,7 @@ public class UnitType extends UnlockableContent{
} }
public UnitController createController(Unit unit){ public UnitController createController(Unit unit){
return unitBasedDefaultController.get(unit); return defaultController.get(unit);
} }
public Unit create(Team team){ public Unit create(Team team){

View File

@@ -19,7 +19,7 @@ public class MissileUnitType extends UnitType{
isCounted = false; isCounted = false;
useUnitCap = false; useUnitCap = false;
allowedInPayloads = false; allowedInPayloads = false;
defaultController = MissileAI::new; aiController = MissileAI::new;
flying = true; flying = true;
constructor = TimedKillUnit::create; constructor = TimedKillUnit::create;
envEnabled = Env.any; envEnabled = Env.any;

View File

@@ -235,6 +235,8 @@ public class CustomRulesDialog extends BaseDialog{
number("@rules.blockhealthmultiplier", f -> teams.blockHealthMultiplier = f, () -> teams.blockHealthMultiplier); number("@rules.blockhealthmultiplier", f -> teams.blockHealthMultiplier = f, () -> teams.blockHealthMultiplier);
number("@rules.blockdamagemultiplier", f -> teams.blockDamageMultiplier = f, () -> teams.blockDamageMultiplier); number("@rules.blockdamagemultiplier", f -> teams.blockDamageMultiplier = f, () -> teams.blockDamageMultiplier);
check("@rules.rtsai", b -> teams.rtsAi = b, () -> teams.rtsAi, () -> team != rules.defaultTeam);
check("@rules.buildai", b -> teams.ai = b, () -> teams.ai, () -> team != rules.defaultTeam); check("@rules.buildai", b -> teams.ai = b, () -> teams.ai, () -> team != rules.defaultTeam);
number("@rules.aitier", false, f -> teams.aiTier = f, () -> teams.aiTier, () -> teams.ai, 0, 1); number("@rules.aitier", false, f -> teams.aiTier = f, () -> teams.aiTier, () -> teams.ai, 0, 1);

View File

@@ -34,7 +34,7 @@ public class DroneCenter extends Block{
public void init(){ public void init(){
super.init(); super.init();
droneType.defaultController = EffectDroneAI::new; droneType.aiController = EffectDroneAI::new;
} }
public class DroneCenterBuild extends Building{ public class DroneCenterBuild extends Building{