diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index c93bd91fed..68ffc71fc4 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1052,6 +1052,7 @@ rules.wavetimer = Wave Timer rules.waves = Waves rules.attack = Attack Mode rules.buildai = AI Building +rules.rtsai = RTS AI rules.aitier = AI Tier rules.cleanupdeadteams = Clean Up Defeated Team Buildings (PvP) rules.corecapture = Capture Core On Destruction diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java index 9b8ef4164f..c362b68551 100644 --- a/core/src/mindustry/ai/BaseAI.java +++ b/core/src/mindustry/ai/BaseAI.java @@ -36,8 +36,8 @@ public class BaseAI{ private int lastX, lastY, lastW, lastH; private boolean triedWalls, foundPath; - TeamData data; - Interval timer = new Interval(4); + final TeamData data; + final Interval timer = new Interval(4); IntSet path = new IntSet(); IntSet calcPath = new IntSet(); diff --git a/core/src/mindustry/ai/RtsAI.java b/core/src/mindustry/ai/RtsAI.java new file mode 100644 index 0000000000..ca2b9c7537 --- /dev/null +++ b/core/src/mindustry/ai/RtsAI.java @@ -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(){ + + } +} diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 597d9967e1..62bcf7e948 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -583,7 +583,7 @@ public class UnitTypes{ //region ground legs crawler = new UnitType("crawler"){{ - defaultController = SuicideAI::new; + aiController = SuicideAI::new; speed = 1f; hitSize = 8f; @@ -1236,7 +1236,7 @@ public class UnitTypes{ //region air support mono = new UnitType("mono"){{ - unitBasedDefaultController = u -> new MinerAI(); + defaultController = u -> new MinerAI(); flying = true; drag = 0.06f; @@ -1255,7 +1255,7 @@ public class UnitTypes{ }}; poly = new UnitType("poly"){{ - unitBasedDefaultController = u -> new BuilderAI(); + defaultController = u -> new BuilderAI(); flying = true; drag = 0.05f; @@ -1311,7 +1311,7 @@ public class UnitTypes{ mega = new UnitType("mega"){{ //TODO control? - defaultController = RepairAI::new; + aiController = RepairAI::new; mineTier = 3; mineSpeed = 4f; @@ -1435,7 +1435,7 @@ public class UnitTypes{ }}; oct = new UnitType("oct"){{ - defaultController = DefenderAI::new; + aiController = DefenderAI::new; armor = 16f; health = 24000; @@ -2301,7 +2301,7 @@ public class UnitTypes{ //region core alpha = new UnitType("alpha"){{ - defaultController = BuilderAI::new; + aiController = BuilderAI::new; isCounted = false; lowAltitude = true; @@ -2338,7 +2338,7 @@ public class UnitTypes{ }}; beta = new UnitType("beta"){{ - defaultController = BuilderAI::new; + aiController = BuilderAI::new; isCounted = false; flying = true; @@ -2379,7 +2379,7 @@ public class UnitTypes{ }}; gamma = new UnitType("gamma"){{ - defaultController = BuilderAI::new; + aiController = BuilderAI::new; isCounted = false; lowAltitude = true; @@ -2922,7 +2922,7 @@ public class UnitTypes{ //region erekir - flying quell = new ErekirUnitType("quell"){{ - defaultController = FlyingFollowAI::new; + aiController = FlyingFollowAI::new; envDisabled = 0; lowAltitude = false; @@ -2988,7 +2988,7 @@ public class UnitTypes{ }}; disrupt = new ErekirUnitType("disrupt"){{ - defaultController = FlyingFollowAI::new; + aiController = FlyingFollowAI::new; envDisabled = 0; lowAltitude = false; @@ -3157,7 +3157,7 @@ public class UnitTypes{ //TODO bad name evoke = new ErekirUnitType("evoke"){{ coreUnitDock = true; - defaultController = BuilderAI::new; + aiController = BuilderAI::new; isCounted = false; envDisabled = 0; @@ -3214,7 +3214,7 @@ public class UnitTypes{ incite = new ErekirUnitType("incite"){{ coreUnitDock = true; - defaultController = BuilderAI::new; + aiController = BuilderAI::new; isCounted = false; envDisabled = 0; @@ -3283,7 +3283,7 @@ public class UnitTypes{ emanate = new ErekirUnitType("emanate"){{ coreUnitDock = true; - defaultController = BuilderAI::new; + aiController = BuilderAI::new; isCounted = false; envDisabled = 0; @@ -3355,7 +3355,7 @@ public class UnitTypes{ }}; manifold = new ErekirUnitType("manifold"){{ - defaultController = CargoAI::new; + aiController = CargoAI::new; isCounted = false; allowedInPayloads = false; logicControllable = false; @@ -3382,7 +3382,7 @@ public class UnitTypes{ }}; assemblyDrone = new ErekirUnitType("assembly-drone"){{ - defaultController = AssemblerAI::new; + aiController = AssemblerAI::new; flying = true; drag = 0.06f; diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 2b4868bdb5..44ce03dd9f 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -3,6 +3,7 @@ package mindustry.core; import arc.*; import arc.math.*; import arc.util.*; +import mindustry.ai.*; import mindustry.annotations.Annotations.*; import mindustry.core.GameState.*; import mindustry.ctype.*; @@ -415,7 +416,13 @@ public class Logic implements ApplicationListener{ for(TeamData data : state.teams.getActive()){ 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(); } } } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index b8459e2504..4dbdd9b6a5 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -201,7 +201,7 @@ public class Rules{ /** A team-specific ruleset. */ public static class TeamRule{ - /** Whether to use building AI. */ + /** Whether to use building AI. TODO remove, it is terrible. */ public boolean ai; /** TODO Tier of blocks/designs that the AI uses for building. [0, 1] */ public float aiTier = 1f; @@ -214,6 +214,9 @@ public class Rules{ /** If true, this team has infinite unit ammo. */ public boolean infiniteAmmo; + /** Enables "RTS" unit AI. TODO wip */ + public boolean rtsAi; + /** How fast unit factories build units. */ public float unitBuildSpeedMultiplier = 1f; /** How much damage any other units deal. */ diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index fdd1f90506..fb17734058 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -222,7 +222,11 @@ public class Teams{ public static class TeamData{ public final Seq cores = new Seq<>(); 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; @@ -248,7 +252,6 @@ public class Teams{ public TeamData(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'. */ diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index 6e605faad3..c67901a980 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -454,13 +454,13 @@ public class ContentParser{ } 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"); } - if(value.has("unitBasedController")){ - unit.unitBasedDefaultController = u -> supply(resolve(value.getString("unitBasedController"), FlyingAI.class)).get(); - value.remove("unitBasedController"); + if(value.has("defaultController")){ + unit.defaultController = u -> supply(resolve(value.getString("defaultController"), FlyingAI.class)).get(); + value.remove("defaultController"); } //read extra default waves diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index d22e6e4b64..a7b5fd3f10 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -114,10 +114,10 @@ public class UnitType extends UnlockableContent{ //TODO different names for these fields. /** The default AI controller to assign on creation. */ - public Prov defaultController = () -> !flying ? new GroundAI() : new FlyingAI(); + public Prov aiController = () -> !flying ? new GroundAI() : new FlyingAI(); /** Function that chooses AI controller based on unit entity. */ //TODO -name is too long - public Func unitBasedDefaultController = u -> !playerControllable || u.team.isAI() ? defaultController.get() : new CommandAI(); + public Func defaultController = u -> !playerControllable || (u.team.isAI() && !u.team.rules().rtsAi) ? aiController.get() : new CommandAI(); public Color outlineColor = Pal.darkerMetal; public int outlineRadius = 3; @@ -218,7 +218,7 @@ public class UnitType extends UnlockableContent{ } public UnitController createController(Unit unit){ - return unitBasedDefaultController.get(unit); + return defaultController.get(unit); } public Unit create(Team team){ diff --git a/core/src/mindustry/type/unit/MissileUnitType.java b/core/src/mindustry/type/unit/MissileUnitType.java index adc20ad0d0..9427075890 100644 --- a/core/src/mindustry/type/unit/MissileUnitType.java +++ b/core/src/mindustry/type/unit/MissileUnitType.java @@ -19,7 +19,7 @@ public class MissileUnitType extends UnitType{ isCounted = false; useUnitCap = false; allowedInPayloads = false; - defaultController = MissileAI::new; + aiController = MissileAI::new; flying = true; constructor = TimedKillUnit::create; envEnabled = Env.any; diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index e6322771db..8a18f2feeb 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -235,6 +235,8 @@ public class CustomRulesDialog extends BaseDialog{ number("@rules.blockhealthmultiplier", f -> teams.blockHealthMultiplier = f, () -> teams.blockHealthMultiplier); 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); number("@rules.aitier", false, f -> teams.aiTier = f, () -> teams.aiTier, () -> teams.ai, 0, 1); diff --git a/core/src/mindustry/world/blocks/units/DroneCenter.java b/core/src/mindustry/world/blocks/units/DroneCenter.java index 6ef14d2441..b079a372a4 100644 --- a/core/src/mindustry/world/blocks/units/DroneCenter.java +++ b/core/src/mindustry/world/blocks/units/DroneCenter.java @@ -34,7 +34,7 @@ public class DroneCenter extends Block{ public void init(){ super.init(); - droneType.defaultController = EffectDroneAI::new; + droneType.aiController = EffectDroneAI::new; } public class DroneCenterBuild extends Building{