From 6e5561a36eefcbdd38c5e37dd2f3f619cd082afe Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 13 Sep 2024 18:50:46 -0400 Subject: [PATCH] Campaign rule for unpredictable wave AI --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/ai/Pathfinder.java | 22 +++++++++++++++++++ core/src/mindustry/ai/types/FlyingAI.java | 22 +++++++++---------- core/src/mindustry/game/CampaignRules.java | 3 ++- core/src/mindustry/game/Rules.java | 4 ++-- .../ui/dialogs/CampaignRulesDialog.java | 1 + 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index c27355fb68..4a89d17453 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1399,6 +1399,7 @@ rules.lighting = Lighting rules.fog = Fog of War rules.invasions = Enemy Sector Invasions rules.showspawns = Show Enemy Spawns +rules.randomwaveai = Unpredictable Wave AI rules.fire = Fire rules.anyenv = rules.explosions = Block/Unit Explosion Damage diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index e93713acc0..e37adc91b0 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -2,6 +2,7 @@ package mindustry.ai; import arc.*; import arc.func.*; +import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; @@ -16,6 +17,7 @@ import mindustry.world.blocks.storage.*; import mindustry.world.meta.*; import static mindustry.Vars.*; +import static mindustry.world.meta.BlockFlag.*; public class Pathfinder implements Runnable{ private static final long maxUpdate = Time.millisToNanos(8); @@ -454,8 +456,28 @@ public class Pathfinder implements Runnable{ } public static class EnemyCoreField extends Flowfield{ + private final static BlockFlag[] randomTargets = {storage, generator, launchPad, factory, repair, battery, reactor, drill}; + private Rand rand = new Rand(); + @Override protected void getPositions(IntSeq out){ + if(state.rules.randomWaveAI && team == state.rules.waveTeam){ + rand.setSeed(state.rules.waves ? state.wave : (int)(state.tick / (5400))); + + //maximum amount of different target flag types they will attack + int max = 2; + + for(int attempt = 0; attempt < 5 && max > 0; attempt++){ + var targets = indexer.getEnemy(team, randomTargets[rand.random(randomTargets.length - 1)]); + if(!targets.isEmpty()){ + max --; + for(Building other : targets){ + out.add(other.tile.array()); + } + } + } + } + for(Building other : indexer.getEnemy(team, BlockFlag.core)){ out.add(other.tile.array()); } diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java index c9eba7a8d9..f7d533658e 100644 --- a/core/src/mindustry/ai/types/FlyingAI.java +++ b/core/src/mindustry/ai/types/FlyingAI.java @@ -45,7 +45,7 @@ public class FlyingAI extends AIController{ return core; } - if(state.rules.randomAirTargeting){ + if(state.rules.randomWaveAI){ //when there are no waves, it's just random based on the unit Mathf.rand.setSeed(unit.type.id + (state.rules.waves ? state.wave : unit.id)); //try a few random flags first @@ -56,17 +56,15 @@ public class FlyingAI extends AIController{ //try the closest target Teamc result = target(x, y, range, air, ground); if(result != null) return result; - //default to the core - return core; - } - - for(var flag : unit.type.targetFlags){ - if(flag == null){ - Teamc result = target(x, y, range, air, ground); - if(result != null) return result; - }else if(ground){ - Teamc result = targetFlag(x, y, flag, true); - if(result != null) return result; + }else{ + for(var flag : unit.type.targetFlags){ + if(flag == null){ + Teamc result = target(x, y, range, air, ground); + if(result != null) return result; + }else if(ground){ + Teamc result = targetFlag(x, y, flag, true); + if(result != null) return result; + } } } diff --git a/core/src/mindustry/game/CampaignRules.java b/core/src/mindustry/game/CampaignRules.java index 10157cc173..3f55661772 100644 --- a/core/src/mindustry/game/CampaignRules.java +++ b/core/src/mindustry/game/CampaignRules.java @@ -5,12 +5,13 @@ public class CampaignRules{ public boolean fog; public boolean showSpawns; public boolean sectorInvasion; + public boolean randomWaveAI; public void apply(Rules rules){ rules.staticFog = rules.fog = fog; rules.showSpawns = showSpawns; + rules.randomWaveAI = randomWaveAI; rules.teams.get(rules.waveTeam).blockHealthMultiplier = difficulty.enemyHealthMultiplier; rules.teams.get(rules.waveTeam).unitHealthMultiplier = difficulty.enemyHealthMultiplier; - rules.randomAirTargeting = difficulty.ordinal() >= Difficulty.hard.ordinal(); } } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index daeec9687d..592be5ddbb 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -61,8 +61,8 @@ public class Rules{ public boolean fire = true; /** Whether units use and require ammo. */ public boolean unitAmmo = false; - /** EXPERIMENTAL! If true, air units target random things each wave instead of only generators. */ - public boolean randomAirTargeting = false; + /** EXPERIMENTAL! If true, air and ground units target random things each wave instead of only the core/generators. */ + public boolean randomWaveAI = false; /** EXPERIMENTAL! If true, blocks will update in units and share power. */ public boolean unitPayloadUpdate = false; /** If true, units' payloads are destroy()ed when the unit is destroyed. */ diff --git a/core/src/mindustry/ui/dialogs/CampaignRulesDialog.java b/core/src/mindustry/ui/dialogs/CampaignRulesDialog.java index 0805234ef8..c528bbcaae 100644 --- a/core/src/mindustry/ui/dialogs/CampaignRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CampaignRulesDialog.java @@ -59,6 +59,7 @@ public class CampaignRulesDialog extends BaseDialog{ check("@rules.fog", b -> rules.fog = b, () -> rules.fog); check("@rules.showspawns", b -> rules.showSpawns = b, () -> rules.showSpawns); + check("@rules.randomwaveai", b -> rules.randomWaveAI = b, () -> rules.randomWaveAI); }).growY(); }