diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index ea660c6eaf..fa50837ef9 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1474,6 +1474,10 @@ rules.cleanupdeadteams = Clean Up Defeated Team Buildings (PvP) rules.corecapture = Capture Core On Destruction rules.polygoncoreprotection = Polygonal Core Protection rules.placerangecheck = Placement Range Check +rules.protectcores = Protect Cores +rules.protectcores.info = When disabled, the core no-build radius won't affect this team.\nPlayers won't be assigned to unprotected teams. +rules.checkplacement = Check Placement +rules.checkplacement.info = When disabled, buildings of this team are ignored in placement range checks. rules.enemyCheat = Infinite Enemy Team Resources rules.blockhealthmultiplier = Block Health Multiplier rules.blockdamagemultiplier = Block Damage Multiplier diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 098002d523..d8b310dfb7 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -52,7 +52,7 @@ public class NetServer implements ApplicationListener{ if(state.rules.pvp){ //find team with minimum amount of players and auto-assign player to that. TeamData re = state.teams.getActive().min(data -> { - if((state.rules.waveTeam == data.team && state.rules.waves) || !data.hasCore() || data.team == Team.derelict) return Integer.MAX_VALUE; + if((state.rules.waveTeam == data.team && state.rules.waves) || !data.hasCore() || data.team == Team.derelict || !data.team.rules().protectCores) return Integer.MAX_VALUE; int count = 0; for(Player other : players){ diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 62b70e6dc2..370909f539 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -248,7 +248,7 @@ public class Rules{ } public float buildRadius(Team team){ - return enemyCoreBuildRadius + teams.get(team).extraCoreBuildRadius; + return !teams.get(team).protectCores ? 0f : enemyCoreBuildRadius + teams.get(team).extraCoreBuildRadius; } public float unitBuildSpeed(Team team){ @@ -299,6 +299,10 @@ public class Rules{ public static class TeamRule{ /** Whether, when AI is enabled, ships should be spawned from the core. TODO remove / unnecessary? */ public boolean aiCoreSpawn = true; + /** Whether the core no-build radius/polygonal protection applies to this team, unprotected teams are ignored by team assigner */ + public boolean protectCores = true; + /** Whether the placeRangeCheck applies to this team */ + public boolean checkPlacement = true; /** If true, blocks don't require power or resources. */ public boolean cheat; /** If true, the core is always filled to capacity with all items. */ @@ -345,8 +349,18 @@ public class Rules{ /** Extra spacing added to the no-build zone around the core. */ public float extraCoreBuildRadius = 0f; - //build cost disabled due to technical complexity + + //for reading from json + public TeamRule(){ + } + + public TeamRule(Team team){ + if(team == Team.derelict){ + protectCores = false; + checkPlacement = false; + } + } } /** A simple map for storing TeamRules in an efficient way without hashing. */ @@ -355,7 +369,7 @@ public class Rules{ public TeamRule get(Team team){ TeamRule out = values[team.id]; - return out == null ? (values[team.id] = new TeamRule()) : out; + return out == null ? (values[team.id] = new TeamRule(team)) : out; } @Override diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index b413e89542..cd08630d9e 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -58,7 +58,7 @@ public class Teams{ public boolean anyEnemyCoresWithinBuildRadius(Team team, float x, float y){ for(TeamData data : active){ - if(team != data.team){ + if(team != data.team && data.team.rules().protectCores){ for(CoreBuild tile : data.cores){ if(tile.within(x, y, state.rules.buildRadius(tile.team) + tilesize)){ return true; @@ -71,7 +71,7 @@ public class Teams{ public boolean anyEnemyCoresWithin(Team team, float x, float y, float radius){ for(TeamData data : active){ - if(team != data.team){ + if(team != data.team && data.team.rules().protectCores){ for(CoreBuild tile : data.cores){ if(tile.within(x, y, radius)){ return true; diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index ee37f6d604..e9c3450503 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -50,8 +50,12 @@ public class OverlayRenderer{ Seq pos = new Seq<>(); Seq teams = new Seq<>(); - for(TeamData team : state.teams.active){ - for(CoreBuild b : team.cores){ + for(TeamData data : state.teams.active){ + if(!data.team.rules().protectCores){ + continue; + } + + for(CoreBuild b : data.cores){ teams.add(b); pos.add(new Vec2(b.x, b.y)); } @@ -179,7 +183,7 @@ public class OverlayRenderer{ state.teams.eachEnemyCore(player.team(), core -> { //it must be clear that there is a core here. float br = state.rules.buildRadius(core.team); - if(/*core.wasVisible && */Core.camera.bounds(Tmp.r1).overlaps(Tmp.r2.setCentered(core.x, core.y, br * 2f))){ + if(/*core.wasVisible && */br > 0f && Core.camera.bounds(Tmp.r1).overlaps(Tmp.r2.setCentered(core.x, core.y, br * 2f))){ Draw.color(Color.darkGray); Lines.circle(core.x, core.y - 2,br); Draw.color(Pal.accent, core.team.color, 0.5f + Mathf.absin(Time.time, 10f, 0.5f)); diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 18335314d5..14cbaa5f62 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -309,7 +309,9 @@ public class CustomRulesDialog extends BaseDialog{ check("@rules.buildai", b -> teams.buildAi = b, () -> teams.buildAi, () -> team != rules.defaultTeam && rules.env != Planets.erekir.defaultEnv && !rules.pvp); number("@rules.buildaitier", false, f -> teams.buildAiTier = f, () -> teams.buildAiTier, () -> teams.buildAi && rules.env != Planets.erekir.defaultEnv && !rules.pvp, 0, 1); - number("@rules.extracorebuildradius", f -> teams.extraCoreBuildRadius = f * tilesize, () -> Math.min(teams.extraCoreBuildRadius / tilesize, 200), () -> !rules.polygonCoreProtection); + check("@rules.protectcores", b -> teams.protectCores = b, () -> teams.protectCores); + number("@rules.extracorebuildradius", f -> teams.extraCoreBuildRadius = f * tilesize, () -> Math.min(teams.extraCoreBuildRadius / tilesize, 200), () -> !rules.polygonCoreProtection && teams.protectCores); + check("@rules.checkplacement", b -> teams.checkPlacement = b, () -> teams.checkPlacement); check("@rules.infiniteresources", b -> teams.infiniteResources = b, () -> teams.infiniteResources); check("@rules.fillitems", b -> teams.fillItems = b, () -> teams.fillItems); diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 0959de0176..2932516666 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -191,6 +191,10 @@ public class Build{ float mindst = Float.MAX_VALUE; CoreBuild closest = null; for(TeamData data : state.teams.active){ + if(!data.team.rules().protectCores){ + continue; + } + for(CoreBuild tile : data.cores){ float dst = tile.dst2(x * tilesize + type.offset, y * tilesize + type.offset); if(dst < mindst){ @@ -265,7 +269,7 @@ public class Build{ } public static @Nullable Building getEnemyOverlap(Block block, Team team, int x, int y){ - return indexer.findEnemyTile(team, x * tilesize + block.size, y * tilesize + block.size, block.placeOverlapRange + 4f, p -> true); + return indexer.findEnemyTile(team, x * tilesize + block.size, y * tilesize + block.size, block.placeOverlapRange + 4f, b -> b.team.rules().checkPlacement); } public static boolean contactsGround(int x, int y, Block block){