diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index fafb869c39..dfefeb2a68 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -61,10 +61,6 @@ public class Vars implements Loadable{ public static final Array defaultServers = Array.with(); /** maximum distance between mine and core that supports automatic transferring */ public static final float mineTransferRange = 220f; - /** team of the player by default */ - public static final Team defaultTeam = Team.sharded; - /** team of the enemy in waves/sectors */ - public static final Team waveTeam = Team.crux; /** whether to enable editing of units in the editor */ public static final boolean enableUnitEditing = false; /** max chat message length */ diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 311e7887a7..bb90b37301 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -103,7 +103,7 @@ public class BlockIndexer{ } private ObjectSet[] getFlagged(Team team){ - return flagMap[(int) team.id]; + return flagMap[(int)team.id]; } /** @return whether this item is present on this map.*/ @@ -115,11 +115,11 @@ public class BlockIndexer{ public ObjectSet getDamaged(Team team){ returnArray.clear(); - if(damagedTiles[(int) team.id] == null){ - damagedTiles[(int) team.id] = new ObjectSet<>(); + if(damagedTiles[(int)team.id] == null){ + damagedTiles[(int)team.id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[(int) team.id]; + ObjectSet set = damagedTiles[(int)team.id]; for(Tile tile : set){ if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); @@ -135,7 +135,7 @@ public class BlockIndexer{ /** Get all allied blocks with a flag. */ public ObjectSet getAllied(Team team, BlockFlag type){ - return flagMap[(int) team.id][type.ordinal()]; + return flagMap[(int)team.id][type.ordinal()]; } /** Get all enemy blocks with a flag. */ @@ -155,11 +155,11 @@ public class BlockIndexer{ } public void notifyTileDamaged(TileEntity entity){ - if(damagedTiles[(int) entity.getTeam().id] == null){ - damagedTiles[(int) entity.getTeam().id] = new ObjectSet<>(); + if(damagedTiles[(int)entity.getTeam().id] == null){ + damagedTiles[(int)entity.getTeam().id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[(int) entity.getTeam().id]; + ObjectSet set = damagedTiles[(int)entity.getTeam().id]; set.add(entity.tile); } @@ -287,11 +287,11 @@ public class BlockIndexer{ //fast-set this quadrant to 'occupied' if the tile just placed is already of this team if(tile.getTeam() == data.team && tile.entity != null && tile.block().targetable){ - structQuadrants[(int) data.team.id].set(quadrantX, quadrantY); + structQuadrants[(int)data.team.id].set(quadrantX, quadrantY); continue; //no need to process futher } - structQuadrants[(int) data.team.id].set(quadrantX, quadrantY, false); + structQuadrants[(int)data.team.id].set(quadrantX, quadrantY, false); outer: for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){ @@ -299,7 +299,7 @@ public class BlockIndexer{ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching if(result.entity != null && result.getTeam() == data.team){ - structQuadrants[(int) data.team.id].set(quadrantX, quadrantY); + structQuadrants[(int)data.team.id].set(quadrantX, quadrantY); break outer; } } @@ -308,7 +308,7 @@ public class BlockIndexer{ } private boolean getQuad(Team team, int quadrantX, int quadrantY){ - return structQuadrants[(int) team.id].get(quadrantX, quadrantY); + return structQuadrants[(int)team.id].get(quadrantX, quadrantY); } private int quadWidth(){ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 9464111cab..319c85ef2e 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -53,7 +53,7 @@ public class Pathfinder implements Runnable{ } //special preset which may help speed things up; this is optional - preloadPath(waveTeam, PathTarget.enemyCores); + preloadPath(state.rules.waveTeam, PathTarget.enemyCores); start(); }); @@ -84,8 +84,8 @@ public class Pathfinder implements Runnable{ } public int debugValue(Team team, int x, int y){ - if(pathMap[(int) team.id][PathTarget.enemyCores.ordinal()] == null) return 0; - return pathMap[(int) team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; + if(pathMap[(int)team.id][PathTarget.enemyCores.ordinal()] == null) return 0; + return pathMap[(int)team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; } /** Update a tile in the internal pathfinding grid. Causes a complete pathfinding reclaculation. */ @@ -149,12 +149,12 @@ public class Pathfinder implements Runnable{ public Tile getTargetTile(Tile tile, Team team, PathTarget target){ if(tile == null) return null; - PathData data = pathMap[(int) team.id][target.ordinal()]; + PathData data = pathMap[(int)team.id][target.ordinal()]; if(data == null){ //if this combination is not found, create it on request - if(!created.get((int) team.id, target.ordinal())){ - created.set((int) team.id, target.ordinal()); + if(!created.get((int)team.id, target.ordinal())){ + created.set((int)team.id, target.ordinal()); //grab targets since this is run on main thread IntArray targets = target.getTargets(team, new IntArray()); queue.post(() -> createPath(team, target, targets)); @@ -188,7 +188,7 @@ public class Pathfinder implements Runnable{ /** @return whether a tile can be passed through by this team. Pathfinding thread only.*/ private boolean passable(int x, int y, Team team){ int tile = tiles[x][y]; - return PathTile.passable(tile) || (PathTile.team(tile) != (int) team.id && PathTile.team(tile) != (int) Team.derelict.id); + return PathTile.passable(tile) || (PathTile.team(tile) != (int)team.id && PathTile.team(tile) != (int)Team.derelict.id); } /** @@ -238,7 +238,7 @@ public class Pathfinder implements Runnable{ PathData path = new PathData(team, target, world.width(), world.height()); list.add(path); - pathMap[(int) team.id][target.ordinal()] = path; + pathMap[(int)team.id][target.ordinal()] = path; //grab targets from passed array synchronized(path.targets){ @@ -303,7 +303,7 @@ public class Pathfinder implements Runnable{ } //spawn points are also enemies. - if(state.rules.waves && team == defaultTeam){ + if(state.rules.waves && team == state.rules.defaultTeam){ for(Tile other : spawner.getGroundSpawns()){ out.add(other.pos()); } diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index ac4914a90b..25b9983db0 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -53,7 +53,7 @@ public class WaveSpawner{ eachFlyerSpawn((spawnX, spawnY) -> { for(int i = 0; i < spawned; i++){ - BaseUnit unit = group.createUnit(waveTeam); + BaseUnit unit = group.createUnit(state.rules.waveTeam); unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread)); unit.add(); } @@ -66,7 +66,7 @@ public class WaveSpawner{ for(int i = 0; i < spawned; i++){ Tmp.v1.rnd(spread); - BaseUnit unit = group.createUnit(waveTeam); + BaseUnit unit = group.createUnit(state.rules.waveTeam); unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y); Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit)); @@ -78,7 +78,7 @@ public class WaveSpawner{ eachGroundSpawn((spawnX, spawnY, doShockwave) -> { if(doShockwave){ Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawnX, spawnY, state.rules.dropZoneRadius)); - Time.run(40f, () -> Damage.damage(waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); + Time.run(40f, () -> Damage.damage(state.rules.waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); } }); @@ -90,9 +90,9 @@ public class WaveSpawner{ cons.accept(spawn.worldx(), spawn.worldy(), true); } - if(state.rules.attackMode && state.teams.isActive(waveTeam) && !state.teams.get(defaultTeam).cores.isEmpty()){ - Tile firstCore = state.teams.get(defaultTeam).cores.first(); - for(Tile core : state.teams.get(waveTeam).cores){ + if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ + Tile firstCore = state.teams.playerCores().first(); + for(Tile core : state.teams.get(state.rules.waveTeam).cores){ Tmp.v1.set(firstCore).sub(core.worldx(), core.worldy()).limit(coreMargin + core.block().size*tilesize); cons.accept(core.worldx() + Tmp.v1.x, core.worldy() + Tmp.v1.y, false); } @@ -107,8 +107,8 @@ public class WaveSpawner{ cons.get(spawnX, spawnY); } - if(state.rules.attackMode && state.teams.isActive(waveTeam)){ - for(Tile core : state.teams.get(waveTeam).cores){ + if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam)){ + for(Tile core : state.teams.get(state.rules.waveTeam).cores){ cons.get(core.worldx(), core.worldy()); } } diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 525a14199c..6672727847 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -6,8 +6,7 @@ import mindustry.entities.Effects; import mindustry.ctype.ContentList; import mindustry.game.EventType.*; import mindustry.type.StatusEffect; - -import static mindustry.Vars.waveTeam; +import static mindustry.Vars.*; public class StatusEffects implements ContentList{ public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked, corroded, boss; @@ -48,7 +47,7 @@ public class StatusEffects implements ContentList{ init(() -> { trans(shocked, ((unit, time, newTime, result) -> { unit.damage(20f); - if(unit.getTeam() == waveTeam){ + if(unit.getTeam() == state.rules.waveTeam){ Events.fire(Trigger.shock); } result.set(this, time); diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index f525494963..ef31948c82 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -63,7 +63,7 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(PlayEvent.class, event -> { - player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam); + player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : state.rules.defaultTeam); player.setDead(true); player.add(); @@ -256,9 +256,9 @@ public class Control implements ApplicationListener, Loadable{ world.loadGenerator(zone.generator); zone.rules.get(state.rules); state.rules.zone = zone; - for(Tile core : state.teams.get(defaultTeam).cores){ + for(TileEntity core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.entity.items.add(stack.item, stack.amount); + core.items.add(stack.item, stack.amount); } } state.set(State.playing); @@ -294,8 +294,8 @@ public class Control implements ApplicationListener, Loadable{ Geometry.circle(coreb.x, coreb.y, 10, (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && tile.getTeam() == defaultTeam && !(tile.block() instanceof CoreBlock)){ - world.removeBlock(tile); + if(tile != null && tile.getTeam() == state.rules.defaultTeam && !(tile.block() instanceof CoreBlock)){ + tile.remove(); } }); @@ -305,13 +305,13 @@ public class Control implements ApplicationListener, Loadable{ zone.rules.get(state.rules); state.rules.zone = zone; - for(Tile core : state.teams.get(defaultTeam).cores){ + for(TileEntity core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.entity.items.add(stack.item, stack.amount); + core.items.add(stack.item, stack.amount); } } - Tile core = state.teams.get(defaultTeam).cores.first(); - core.entity.items.clear(); + TileEntity core = state.teams.playerCores().first(); + core.items.clear(); logic.play(); state.rules.waveTimer = false; @@ -434,9 +434,9 @@ public class Control implements ApplicationListener, Loadable{ input.update(); if(world.isZone()){ - for(Tile tile : state.teams.get(player.getTeam()).cores){ + for(TileEntity tile : state.teams.cores(player.getTeam())){ for(Item item : content.items()){ - if(tile.entity != null && tile.entity.items.has(item)){ + if(tile.items.has(item)){ data.unlockContent(item); } } diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index eb7d419a10..2b233789eb 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -26,7 +26,7 @@ public class GameState{ private State state = State.menu; public BaseUnit boss(){ - return unitGroup.find(u -> u.isBoss() && u.getTeam() == waveTeam); + return unitGroup.find(u -> u.isBoss() && u.getTeam() == rules.waveTeam); } public void set(State astate){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 86061bc6c6..17fedab303 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -107,9 +107,9 @@ public class Logic implements ApplicationListener{ //add starting items if(!world.isZone()){ - for(Team team : Team.all){ - if(!state.teams.get(team).cores.isEmpty()){ - TileEntity entity = state.teams.get(team).cores.first().entity; + for(TeamData team : state.teams.getActive()){ + if(team.hasCore()){ + TileEntity entity = team.core(); entity.items.clear(); for(ItemStack stack : state.rules.loadout){ entity.items.add(stack.item, stack.amount); @@ -143,23 +143,23 @@ public class Logic implements ApplicationListener{ } private void checkGameOver(){ - if(!state.rules.attackMode && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){ + if(!state.rules.attackMode && state.teams.playerCores().size == 0 && !state.gameOver){ state.gameOver = true; - Events.fire(new GameOverEvent(waveTeam)); + Events.fire(new GameOverEvent(state.rules.waveTeam)); }else if(state.rules.attackMode){ Team alive = null; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size > 0){ + for(TeamData team : state.teams.getActive()){ + if(team.hasCore()){ if(alive != null){ return; } - alive = team; + alive = team.team; } } if(alive != null && !state.gameOver){ - if(world.isZone() && alive == defaultTeam){ + if(world.isZone() && alive == state.rules.defaultTeam){ //in attack maps, a victorious game over is equivalent to a launch Call.launchZone(); }else{ @@ -176,7 +176,7 @@ public class Logic implements ApplicationListener{ ui.hudfrag.showLaunch(); } - for(Tile tile : state.teams.get(defaultTeam).cores){ + for(TileEntity tile : state.teams.playerCores()){ Effects.effect(Fx.launch, tile); } @@ -185,19 +185,18 @@ public class Logic implements ApplicationListener{ } Time.runTask(30f, () -> { - for(Tile tile : state.teams.get(defaultTeam).cores){ + for(TileEntity entity : state.teams.playerCores()){ for(Item item : content.items()){ - if(tile == null || tile.entity == null || tile.entity.items == null) continue; - data.addItem(item, tile.entity.items.get(item)); - Events.fire(new LaunchItemEvent(item, tile.entity.items.get(item))); + data.addItem(item, entity.items.get(item)); + Events.fire(new LaunchItemEvent(item, entity.items.get(item))); } - world.removeBlock(tile); + entity.tile.remove(); } state.launched = true; state.gameOver = true; Events.fire(new LaunchEvent()); //manually fire game over event now - Events.fire(new GameOverEvent(defaultTeam)); + Events.fire(new GameOverEvent(state.rules.defaultTeam)); }); } @@ -213,7 +212,7 @@ public class Logic implements ApplicationListener{ if(!state.is(State.menu)){ if(!net.client()){ - state.enemies = unitGroup.count(b -> b.getTeam() == waveTeam && b.countsAsEnemy()); + state.enemies = unitGroup.count(b -> b.getTeam() == state.rules.waveTeam && b.countsAsEnemy()); } if(!state.isPaused()){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 4c86ecb9d0..3e325e5b31 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -17,11 +17,13 @@ import mindustry.entities.traits.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.net.*; import mindustry.net.Administration.*; import mindustry.net.Packets.*; import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; import java.io.*; import java.nio.*; @@ -402,18 +404,16 @@ public class NetServer implements ApplicationListener{ public Team assignTeam(Player current, Iterable players){ //find team with minimum amount of players and auto-assign player to that. - return Structs.findMin(Team.all, team -> { - if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){ - int count = 0; - for(Player other : players){ - if(other.getTeam() == team && other != current){ - count++; - } + TeamData re = state.teams.getActive().min(data -> { + int count = 0; + for(Player other : players){ + if(other.getTeam() == data.team && other != current){ + count++; } - return count; } - return Integer.MAX_VALUE; + return count; }); + return re == null ? null : re.team; } public void sendWorldData(Player player){ @@ -584,8 +584,8 @@ public class NetServer implements ApplicationListener{ public boolean isWaitingForPlayers(){ if(state.rules.pvp){ int used = 0; - for(Team t : Team.all){ - if(playerGroup.count(p -> p.getTeam() == t) > 0){ + for(TeamData t : state.teams.getActive()){ + if(playerGroup.count(p -> p.getTeam() == t.team) > 0){ used++; } } @@ -647,13 +647,13 @@ public class NetServer implements ApplicationListener{ public void writeEntitySnapshot(Player player) throws IOException{ syncStream.reset(); - ObjectSet cores = state.teams.get(player.getTeam()).cores; + Array cores = state.teams.cores(player.getTeam()); dataStream.writeByte(cores.size); - for(Tile tile : cores){ - dataStream.writeInt(tile.pos()); - tile.entity.items.write(dataStream); + for(CoreEntity entity : cores){ + dataStream.writeInt(entity.tile.pos()); + entity.items.write(dataStream); } dataStream.close(); diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 2a7cd16922..94528a62d8 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -18,11 +18,10 @@ import mindustry.entities.effect.*; import mindustry.entities.effect.GroundEffectEntity.*; import mindustry.entities.traits.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.input.*; -import mindustry.ui.Cicon; +import mindustry.ui.*; import mindustry.world.blocks.defense.ForceProjector.*; import static arc.Core.*; @@ -344,11 +343,7 @@ public class Renderer implements ApplicationListener{ Draw.rect("circle-shadow", u.x, u.y, size * rad, size * rad); }; - for(EntityGroup group : unitGroups){ - if(!group.isEmpty()){ - group.draw(unit -> !unit.isDead(), draw::get); - } - } + unitGroup.draw(unit -> !unit.isDead(), draw::get); if(!playerGroup.isEmpty()){ playerGroup.draw(unit -> !unit.isDead(), draw::get); @@ -361,34 +356,21 @@ public class Renderer implements ApplicationListener{ float trnsX = -12, trnsY = -13; Draw.color(0, 0, 0, 0.22f); - for(EntityGroup group : unitGroups){ - if(!group.isEmpty()){ - group.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); - } - } - - if(!playerGroup.isEmpty()){ - playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); - } + unitGroup.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); + playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); Draw.color(); } private void drawAllTeams(boolean flying){ - for(Team team : Team.all){ - EntityGroup group = unitGroups[(int) team.id]; + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); + playerGroup.draw(p -> p.isFlying() == flying && !p.isDead(), Unit::drawUnder); - if(group.count(p -> p.isFlying() == flying) + playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); + playerGroup.draw(p -> p.isFlying() == flying, Unit::drawAll); - unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder); - - unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll); - - unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); - } + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); + playerGroup.draw(p -> p.isFlying() == flying, Unit::drawOver); } public void scaleCamera(float amount){ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 3cdd2ca4f9..ea0e9aa054 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -1,15 +1,15 @@ package mindustry.core; import arc.*; -import arc.struct.*; import arc.math.*; import arc.math.geom.*; -import arc.util.*; +import arc.struct.*; import arc.util.ArcAnnotate.*; -import mindustry.content.*; +import arc.util.*; import mindustry.core.GameState.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.io.*; import mindustry.maps.*; import mindustry.maps.filters.*; @@ -233,33 +233,22 @@ public class World{ invalidMap = false; if(!headless){ - if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){ + if(state.teams.playerCores().size == 0 && !checkRules.pvp){ ui.showErrorMessage("$map.nospawn"); invalidMap = true; }else if(checkRules.pvp){ //pvp maps need two cores to be valid - int teams = 0; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size != 0){ - teams ++; - } - } - if(teams < 2){ + if(state.teams.getActive().count(TeamData::hasCore) < 2){ invalidMap = true; ui.showErrorMessage("$map.nospawn.pvp"); } }else if(checkRules.attackMode){ //attack maps need two cores to be valid - invalidMap = state.teams.get(waveTeam).cores.isEmpty(); + invalidMap = state.teams.get(state.rules.waveTeam).noCores(); if(invalidMap){ ui.showErrorMessage("$map.nospawn.attack"); } } }else{ - invalidMap = true; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size != 0){ - invalidMap = false; - } - } + invalidMap = !state.teams.getActive().contains(TeamData::hasCore); if(invalidMap){ throw new MapException(map, "Map has no cores!"); @@ -275,36 +264,6 @@ public class World{ } } - public void removeBlock(Tile tile){ - if(tile == null) return; - tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air)); - } - - public void setBlock(Tile tile, Block block, Team team){ - setBlock(tile, block, team, 0); - } - - public void setBlock(Tile tile, Block block, Team team, int rotation){ - tile.setBlock(block, team, rotation); - if(block.isMultiblock()){ - int offsetx = -(block.size - 1) / 2; - int offsety = -(block.size - 1) / 2; - - for(int dx = 0; dx < block.size; dx++){ - for(int dy = 0; dy < block.size; dy++){ - int worldx = dx + offsetx + tile.x; - int worldy = dy + offsety + tile.y; - if(!(worldx == tile.x && worldy == tile.y)){ - Tile toplace = world.tile(worldx, worldy); - if(toplace != null){ - toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); - } - } - } - } - } - } - public void raycastEachWorld(float x0, float y0, float x1, float y1, Raycaster cons){ raycastEach(toTile(x0), toTile(y0), toTile(x1), toTile(y1), cons); } diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 22a7ad5730..061a7aee84 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -69,7 +69,7 @@ public class DrawOperation{ }else if(type == OpType.rotation.ordinal()){ tile.rotation(to); }else if(type == OpType.team.ordinal()){ - tile.setTeam(Team.all[to]); + tile.setTeam(Team.get(to)); }else if(type == OpType.overlay.ordinal()){ tile.setOverlayID(to); } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index f9d00b8903..4a9effccfd 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -74,7 +74,7 @@ public class EditorTile extends Tile{ return; } - if(getTeamID() == (int) team.id) return; + if(getTeamID() == (int)team.id) return; op(OpType.team, getTeamID()); super.setTeam(team); } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index a2a6927398..50442ff0f2 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -1,15 +1,14 @@ package mindustry.editor; -import arc.struct.IntArray; import arc.func.*; -import arc.math.Mathf; -import arc.math.geom.Bresenham2; -import arc.util.Structs; -import mindustry.Vars; -import mindustry.content.Blocks; -import mindustry.game.Team; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.game.*; import mindustry.world.*; -import mindustry.world.blocks.BlockPart; +import mindustry.world.blocks.*; public enum EditorTool{ zoom, @@ -80,7 +79,7 @@ public enum EditorTool{ editor.drawCircle(x, y, tile -> { if(mode == -1){ //erase block - Vars.world.removeBlock(tile); + tile.remove(); }else if(mode == 0){ //erase ore tile.clearOverlay(); @@ -141,7 +140,7 @@ public enum EditorTool{ if(tile.link().synthetic()){ Team dest = tile.getTeam(); if(dest == editor.drawTeam) return; - fill(editor, x, y, false, t -> t.getTeamID() == (int) dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); + fill(editor, x, y, false, t -> t.getTeamID() == (int)dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); } } } diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index c83c754b4e..7cab015b1f 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -10,7 +10,6 @@ import arc.util.Structs; import mindustry.content.Blocks; import mindustry.game.Team; import mindustry.gen.TileOp; -import mindustry.io.LegacyMapIO; import mindustry.io.MapIO; import mindustry.maps.Map; import mindustry.world.*; @@ -65,7 +64,7 @@ public class MapEditor{ reset(); createTiles(pixmap.getWidth(), pixmap.getHeight()); - load(() -> LegacyMapIO.readPixmap(pixmap, tiles())); + load(() -> MapIO.readPixmap(pixmap, tiles())); renderer.resize(width(), height()); } @@ -86,7 +85,7 @@ public class MapEditor{ for(int x = 0; x < width(); x++){ for(int y = 0; y < height(); y++){ if(tiles[x][y].block().isMultiblock()){ - world.setBlock(tiles[x][y], tiles[x][y].block(), tiles[x][y].getTeam()); + tiles[x][y].set(tiles[x][y].block(), tiles[x][y].getTeam()); } } } @@ -176,7 +175,7 @@ public class MapEditor{ } } - world.setBlock(tile(x, y), drawBlock, drawTeam); + tile(x, y).set(drawBlock, drawTeam); }else{ boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; @@ -185,7 +184,7 @@ public class MapEditor{ //remove linked tiles blocking the way if(!isFloor && (tile.isLinked() || tile.block().isMultiblock())){ - world.removeBlock(tile.link()); + tile.link().remove(); } if(isFloor){ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 0ee0fca085..b9a28501b9 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -551,7 +551,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ int i = 0; - for(Team team : Team.all){ + for(Team team : Team.base()){ ImageButton button = new ImageButton(Tex.whiteui, Styles.clearTogglePartiali); button.margin(4f); button.getImageCell().grow(); diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 976d7fc3b2..8704b8a209 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -138,7 +138,7 @@ public class MapGenerateDialog extends FloatingDialog{ tile.rotation(write.rotation); tile.setFloor((Floor)content.block(write.floor)); tile.setBlock(content.block(write.block)); - tile.setTeam(Team.all[write.team]); + tile.setTeam(Team.get(write.team)); tile.setOverlay(content.block(write.ore)); } } @@ -367,7 +367,7 @@ public class MapGenerateDialog extends FloatingDialog{ GenTile tile = buffer1[px][py]; input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); filter.apply(input); - buffer2[px][py].set(input.floor, input.block, input.ore, Team.all[tile.team], tile.rotation); + buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team), tile.rotation); } } for(int px = 0; px < pixmap.getWidth(); px++){ @@ -415,7 +415,7 @@ public class MapGenerateDialog extends FloatingDialog{ this.floor = floor.id; this.block = wall.id; this.ore = ore.id; - this.team = (byte) (int) team.id; + this.team = (byte) (int)team.id; this.rotation = (byte)rotation; } @@ -437,7 +437,7 @@ public class MapGenerateDialog extends FloatingDialog{ ctile.setBlock(content.block(block)); ctile.setOverlay(content.block(ore)); ctile.rotation(rotation); - ctile.setTeam(Team.all[team]); + ctile.setTeam(Team.get(team)); return ctile; } } diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index a9bdd04f3f..3fe1b00d31 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -88,7 +88,7 @@ public class Damage{ tr.trns(angle, length); Intc2 collider = (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != (int) team.id && tile.entity.collide(hitter)){ + if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != (int)team.id && tile.entity.collide(hitter)){ tile.entity.collision(hitter); collidedBlocks.add(tile.pos()); hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index ad228556b8..09e0293241 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -157,7 +157,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - unitGroups[(int) team.id].intersect(x, y, width, height, cons); + unitGroups[(int)team.id].intersect(x, y, width, height, cons); playerGroup.intersect(x, y, width, height, player -> { if(player.getTeam() == team){ cons.get(player); @@ -167,7 +167,7 @@ public class Units{ /** Iterates over all units in a circle around this position. */ public static void nearby(Team team, float x, float y, float radius, Cons cons){ - unitGroups[(int) team.id].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { + unitGroups[(int)team.id].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { if(unit.withinDst(x, y, radius)){ cons.get(unit); } @@ -183,7 +183,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(float x, float y, float width, float height, Cons cons){ for(Team team : Team.all){ - unitGroups[(int) team.id].intersect(x, y, width, height, cons); + unitGroups[(int)team.id].intersect(x, y, width, height, cons); } playerGroup.intersect(x, y, width, height, cons); @@ -199,7 +199,7 @@ public class Units{ EnumSet targets = state.teams.enemiesOf(team); for(Team other : targets){ - unitGroups[(int) other.id].intersect(x, y, width, height, cons); + unitGroups[(int)other.id].intersect(x, y, width, height, cons); } playerGroup.intersect(x, y, width, height, player -> { @@ -216,10 +216,7 @@ public class Units{ /** Iterates over all units. */ public static void all(Cons cons){ - for(Team team : Team.all){ - unitGroups[(int) team.id].all().each(cons); - } - + unitGroup.all().each(cons); playerGroup.all().each(cons); } diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index 28a6eea861..03b4f2d0de 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -185,23 +185,16 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } } - public Tile getClosest(BlockFlag flag){ + public @Nullable Tile getClosest(BlockFlag flag){ return Geometry.findClosest(x, y, indexer.getAllied(team, flag)); } - public Tile getClosestSpawner(){ + public @Nullable Tile getClosestSpawner(){ return Geometry.findClosest(x, y, Vars.spawner.getGroundSpawns()); } - public TileEntity getClosestEnemyCore(){ - for(Team enemy : Vars.state.teams.enemiesOf(team)){ - Tile tile = Geometry.findClosest(x, y, Vars.state.teams.get(enemy).cores); - if(tile != null){ - return tile.entity; - } - } - - return null; + public @Nullable TileEntity getClosestEnemyCore(){ + return Vars.state.teams.closestEnemyCore(x, y, team); } public UnitState getStartState(){ @@ -370,7 +363,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ @Override public EntityGroup targetGroup(){ - return unitGroups[(int) team.id]; + return unitGroup; } @Override diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java index 85c6c9d2eb..4a2a5aee91 100644 --- a/core/src/mindustry/entities/type/TileEntity.java +++ b/core/src/mindustry/entities/type/TileEntity.java @@ -124,7 +124,8 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @CallSuper public void write(DataOutput stream) throws IOException{ stream.writeShort((short)health); - stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation + stream.writeByte(Pack.byteByte((byte)8, tile.rotation())); //rotation + marker to indicate that team is moved (8 isn't valid) + stream.writeByte(tile.getTeamID()); if(items != null) items.write(stream); if(power != null) power.write(stream); if(liquids != null) liquids.write(stream); @@ -134,11 +135,11 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @CallSuper public void read(DataInput stream, byte revision) throws IOException{ health = stream.readUnsignedShort(); - byte tr = stream.readByte(); - byte team = Pack.leftByte(tr); - byte rotation = Pack.rightByte(tr); + byte packedrot = stream.readByte(); + byte team = Pack.leftByte(packedrot) == 8 ? stream.readByte() : Pack.leftByte(packedrot); + byte rotation = Pack.rightByte(packedrot); - tile.setTeam(Team.all[team]); + tile.setTeam(Team.get(team)); tile.rotation(rotation); if(items != null) items.read(stream); @@ -277,7 +278,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ Events.fire(new BlockDestroyEvent(tile)); block.breakSound.at(tile); block.onDestroyed(tile); - world.removeBlock(tile); + tile.remove(); remove(); } } diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index 81ec1de7cb..0b0ccc277a 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -1,12 +1,12 @@ package mindustry.entities.type; import arc.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.content.*; @@ -16,13 +16,11 @@ import mindustry.entities.traits.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; -import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; import mindustry.type.*; import mindustry.ui.*; -import mindustry.ui.Cicon; import mindustry.world.*; import mindustry.world.blocks.*; @@ -158,7 +156,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ this.item.amount = itemAmount; this.item.item = content.item(itemID); this.dead = dead; - this.team = Team.all[team]; + this.team = Team.get(team); this.health = health; this.x = x; this.y = y; @@ -169,7 +167,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public void writeSave(DataOutput stream, boolean net) throws IOException{ if(item.item == null) item.item = Items.copper; - stream.writeByte((int) team.id); + stream.writeByte((int)team.id); stream.writeBoolean(isDead()); stream.writeFloat(net ? interpolator.target.x : x); stream.writeFloat(net ? interpolator.target.y : y); @@ -217,13 +215,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ float fsize = getSize() / radScl; moveVector.setZero(); float cx = x - fsize/2f, cy = y - fsize/2f; - - for(Team team : Team.all){ - if(team != getTeam() || !(this instanceof Player)){ - avoid(unitGroups[(int) team.id].intersect(cx, cy, fsize, fsize)); - } - } - + avoid(unitGroup.intersect(cx, cy, fsize, fsize)); if(!(this instanceof Player)){ avoid(playerGroup.intersect(cx, cy, fsize, fsize)); } @@ -242,14 +234,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public @Nullable TileEntity getClosestCore(){ - TeamData data = state.teams.get(team); - - Tile tile = Geometry.findClosest(x, y, data.cores); - if(tile == null){ - return null; - }else{ - return tile.entity; - } + return state.teams.closestCore(x, y, team); } public Floor getFloorOn(){ @@ -275,7 +260,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } //apply knockback based on spawns - if(getTeam() != waveTeam){ + if(getTeam() != state.rules.waveTeam){ float relativeSize = state.rules.dropZoneRadius + getSize()/2f + 1f; for(Tile spawn : spawner.getGroundSpawns()){ if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){ diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java index aad348b9ce..83d4606122 100644 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/mindustry/entities/type/base/BuilderDrone.java @@ -114,7 +114,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ public BuilderDrone(){ if(reset.check()){ Events.on(BuildSelectEvent.class, event -> { - EntityGroup group = unitGroups[(int) event.team.id]; + EntityGroup group = unitGroups[(int)event.team.id]; if(!(event.tile.entity instanceof BuildEntity)) return; diff --git a/core/src/mindustry/entities/units/UnitDrops.java b/core/src/mindustry/entities/units/UnitDrops.java index b58171ee2f..f57ff0a75d 100644 --- a/core/src/mindustry/entities/units/UnitDrops.java +++ b/core/src/mindustry/entities/units/UnitDrops.java @@ -7,13 +7,14 @@ import mindustry.entities.type.BaseUnit; import mindustry.entities.type.TileEntity; import mindustry.gen.Call; import mindustry.type.Item; +import static mindustry.Vars.*; public class UnitDrops{ private static Item[] dropTable; public static void dropItems(BaseUnit unit){ //items only dropped in waves for enemy team - if(unit.getTeam() != Vars.waveTeam || !Vars.state.rules.unitDrops){ + if(unit.getTeam() != state.rules.waveTeam || !Vars.state.rules.unitDrops){ return; } diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java index aca4d3340e..3679ba0ad2 100644 --- a/core/src/mindustry/game/Gamemode.java +++ b/core/src/mindustry/game/Gamemode.java @@ -4,7 +4,7 @@ import arc.*; import arc.func.*; import mindustry.maps.*; -import static mindustry.Vars.waveTeam; +import static mindustry.Vars.*; /** Defines preset rule sets. */ public enum Gamemode{ @@ -22,7 +22,7 @@ public enum Gamemode{ attack(rules -> { rules.unitDrops = true; rules.attackMode = true; - }, map -> map.teams.contains((int) waveTeam.id)), + }, map -> map.teams.contains((int)state.rules.waveTeam.id)), pvp(rules -> { rules.pvp = true; rules.enemyCoreBuildRadius = 600f; diff --git a/core/src/mindustry/game/MusicControl.java b/core/src/mindustry/game/MusicControl.java index f4352f28be..26a44876ac 100644 --- a/core/src/mindustry/game/MusicControl.java +++ b/core/src/mindustry/game/MusicControl.java @@ -83,7 +83,7 @@ public class MusicControl{ /** Whether to play dark music.*/ private boolean isDark(){ - if(!state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity.healthf() < 0.85f){ + if(state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().healthf() < 0.85f){ //core damaged -> dark return true; } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 8b40abd1ae..d910952021 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -78,6 +78,10 @@ public class Rules{ public boolean lighting = false; /** Ambient light color, used when lighting is enabled. */ public Color ambientLight = new Color(0.01f, 0.01f, 0.04f, 0.99f); + /** team of the player by default */ + public Team defaultTeam = Team.sharded; + /** team of the enemy in waves/sectors */ + public Team waveTeam = Team.crux; /** Copies this ruleset exactly. Not very efficient at all, do not use often. */ public Rules copy(){ diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index b9c56744a3..b30658692e 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -254,7 +254,7 @@ public class Schematics implements Loadable{ Tile tile = world.tile(st.x + ox, st.y + oy); if(tile == null) return; - world.setBlock(tile, st.block, defaultTeam); + tile.set(st.block, state.rules.defaultTeam); tile.rotation(st.rotation); if(st.block.posConfig){ tile.configureAny(Pos.get(tile.x - st.x + Pos.x(st.config), tile.y - st.y + Pos.y(st.config))); diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index a64e5fd127..a97d84a70b 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -2,34 +2,66 @@ package mindustry.game; import arc.*; import arc.graphics.*; -import arc.struct.*; +import arc.util.*; import mindustry.graphics.*; -public class Team{ - /** All registered teams. */ - public final static Array all = new Array<>(); - public final static Team - derelict = new Team("derelict", Color.valueOf("4d4e58")), - sharded = new Team("sharded", Pal.accent.cpy()), - crux = new Team("crux", Color.valueOf("e82d2d")), - green = new Team("green", Color.valueOf("4dd98b")), - purple = new Team("purple", Color.valueOf("9a4bdf")), - blue = new Team("blue", Color.royal.cpy()); - +public class Team implements Comparable{ public final Color color; public final int intColor; public final String name; - public final int id; + public final byte id; - public Team(String name, Color color){ + /** All 256 registered teams. */ + private static final Team[] all = new Team[256]; + /** The 6 base teams used in the editor. */ + private static final Team[] baseTeams = new Team[6]; + + public final static Team + derelict = new Team(0, "derelict", Color.valueOf("4d4e58")), + sharded = new Team(1, "sharded", Pal.accent.cpy()), + crux = new Team(2, "crux", Color.valueOf("e82d2d")), + green = new Team(3, "green", Color.valueOf("4dd98b")), + purple = new Team(4, "purple", Color.valueOf("9a4bdf")), + blue = new Team(5, "blue", Color.royal.cpy()); + + static{ + //create the whole 256 placeholder teams + for(int i = 6; i < all.length; i++){ + new Team(i, "team#" + i, Color.HSVtoRGB(360f * (float)(i) / all.length, 100f, 100f, 1f)); + } + } + + public static Team get(int id){ + return all[Pack.u((byte)id)]; + } + + /** @return the 6 base team colors. */ + public static Team[] base(){ + return baseTeams; + } + + /** @return all the teams - do not use this for lookup! */ + public static Team[] all(){ + return all; + } + + protected Team(int id, String name, Color color){ this.name = name; this.color = color; this.intColor = Color.rgba8888(color); - this.id = all.size; - all.add(this); + this.id = (byte)id; + + int us = Pack.u(this.id); + if(us < 6) baseTeams[us] = this; + all[us] = this; } public String localized(){ - return Core.bundle.get("team." + name + ".name"); + return Core.bundle.get("team." + name + ".name", name); + } + + @Override + public int compareTo(Team team){ + return Integer.compare(id, team.id); } } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index d77b7902ae..d5d033ec46 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -1,44 +1,82 @@ package mindustry.game; import arc.func.*; +import arc.math.geom.*; import arc.struct.*; -import mindustry.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; import mindustry.entities.type.*; -import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.state; /** Class for various team-based utilities. */ public class Teams{ /** Maps team IDs to team data. */ - private Array map = new Array<>(); + private TeamData[] map = new TeamData[256]; /** Active teams. */ private Array active = new Array<>(); - public T eachEnemyCore(Team team, Func ret){ - T out = null; - //todo each enemy, each enemy core... - return out; + public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + CoreEntity tile = Geometry.findClosest(x, y, data.cores); + if(tile != null){ + return tile; + } + } + } + return null; } - /** - * Register a team. - * @param team The team type enum. - */ - public void add(Team team){ - map[team.id] = new TeamData(team); + public @Nullable CoreEntity closestCore(float x, float y, Team team){ + return Geometry.findClosest(x, y, get(team).cores); + } + + public boolean eachEnemyCore(Team team, Boolf ret){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + for(CoreEntity tile : data.cores){ + if(ret.get(tile)){ + return true; + } + } + } + } + return false; + } + + public void eachEnemyCore(Team team, Cons ret){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + for(TileEntity tile : data.cores){ + ret.get(tile); + } + } + } } /** Returns team data by type. */ public TeamData get(Team team){ - if(map[team.id] == null){ - add(team); + if(map[Pack.u(team.id)] == null){ + map[Pack.u(team.id)] = new TeamData(team); } - return map[team.id]; + return map[Pack.u(team.id)]; + } + + public Array playerCores(){ + return get(state.rules.defaultTeam).cores; + } + + /** Do not modify! */ + public Array cores(Team team){ + return get(team).cores; } /** Returns whether a team is active, e.g. whether it has any cores remaining. */ public boolean isActive(Team team){ //the enemy wave team is always active - return team == Vars.waveTeam || get(team).cores.size > 0; + return team == state.rules.waveTeam || get(team).cores.size > 0; } /** Returns whether {@param other} is an enemy of {@param #team}. */ @@ -47,20 +85,63 @@ public class Teams{ return team != other; } - /** Allocates a new array with the active teams. - * Never call in the main game loop.*/ - public Array getActive(){ - return Array.select(map, t -> t != null); + public boolean canInteract(Team team, Team other){ + return team == other || other == Team.derelict; } - public static class TeamData{ - public final ObjectSet cores = new ObjectSet<>(); + /** Do not modify. */ + public Array getActive(){ + return active; + } + + public void registerCore(CoreEntity core){ + TeamData data = get(core.getTeam()); + //add core if not present + if(!data.cores.contains(core)){ + data.cores.add(core); + } + + //register in active list if needed + if(data.active() && !active.contains(data)){ + active.add(data); + } + } + + public void unregisterCore(CoreEntity entity){ + TeamData data = get(entity.getTeam()); + //remove core + data.cores.remove(entity); + //unregister in active list + if(!data.active()){ + active.remove(data); + } + } + + public class TeamData{ + private final Array cores = new Array<>(); + public final Team team; public Queue brokenBlocks = new Queue<>(); public TeamData(Team team){ this.team = team; } + + public boolean active(){ + return team == state.rules.waveTeam || cores.size > 0; + } + + public boolean hasCore(){ + return cores.size > 0; + } + + public boolean noCores(){ + return cores.isEmpty(); + } + + public TileEntity core(){ + return cores.first(); + } } /** Represents a block made by this team that was destroyed somewhere on the map. diff --git a/core/src/mindustry/game/Tutorial.java b/core/src/mindustry/game/Tutorial.java index 569fbd380c..300ab01283 100644 --- a/core/src/mindustry/game/Tutorial.java +++ b/core/src/mindustry/game/Tutorial.java @@ -10,6 +10,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.content.*; +import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; @@ -161,7 +162,7 @@ public class Tutorial{ }, withdraw(() -> event("withdraw")){ void begin(){ - state.teams.get(defaultTeam).cores.first().entity.items.add(Items.copper, 10); + state.teams.playerCores().first().items.add(Items.copper, 10); } }, deposit(() -> event("deposit")), @@ -239,18 +240,18 @@ public class Tutorial{ //utility static void placeBlocks(){ - Tile core = state.teams.get(defaultTeam).cores.first(); + TileEntity core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - world.removeBlock(world.ltile(core.x + blockOffset, core.y + i)); - world.tile(core.x + blockOffset, core.y + i).setBlock(Blocks.scrapWall, defaultTeam); + world.ltile(core.tile.x + blockOffset, core.tile.y + i).remove(); + world.tile(core.tile.x + blockOffset, core.tile.y + i).setBlock(Blocks.scrapWall, state.rules.defaultTeam); } } static boolean blocksBroken(){ - Tile core = state.teams.get(defaultTeam).cores.first(); + TileEntity core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - if(world.tile(core.x + blockOffset, core.y + i).block() == Blocks.scrapWall){ + if(world.tile(core.tile.x + blockOffset, core.tile.y + i).block() == Blocks.scrapWall){ return false; } } @@ -270,7 +271,7 @@ public class Tutorial{ } static int item(Item item){ - return state.teams.get(defaultTeam).cores.isEmpty() ? 0 : state.teams.get(defaultTeam).cores.first().entity.items.get(item); + return state.teams.get(state.rules.defaultTeam).noCores() ? 0 : state.teams.playerCores().first().items.get(item); } static boolean toggled(String name){ diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index 3001159c74..3c65c1b9f4 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -10,13 +10,12 @@ import mindustry.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.input.*; -import mindustry.type.Category; -import mindustry.ui.Cicon; +import mindustry.type.*; +import mindustry.ui.*; import mindustry.world.*; -import mindustry.world.blocks.units.MechPad; -import mindustry.world.meta.BlockFlag; +import mindustry.world.blocks.units.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -95,17 +94,15 @@ public class OverlayRenderer{ Lines.stroke(buildFadeTime * 2f); if(buildFadeTime > 0.005f){ - for(Team enemy : state.teams.enemiesOf(player.getTeam())){ - for(Tile core : state.teams.get(enemy).cores){ - float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy()); - if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ - Draw.color(Color.darkGray); - Lines.circle(core.drawx(), core.drawy() - 2, state.rules.enemyCoreBuildRadius); - Draw.color(Pal.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); - Lines.circle(core.drawx(), core.drawy(), state.rules.enemyCoreBuildRadius); - } + state.teams.eachEnemyCore(player.getTeam(), core -> { + float dst = core.dst(player); + if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ + Draw.color(Color.darkGray); + Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius); + Draw.color(Pal.accent, core.getTeam().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); + Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius); } - } + }); } Lines.stroke(2f); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index b156c3f7f4..38aa0c2fd4 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -397,7 +397,7 @@ public class DesktopInput extends InputHandler{ } if(mode == placing && block != null){ - if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){ + if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int)Core.input.axisTap(Binding.rotate) != 0)){ rotation = ((int)((Angles.angle(selectX, selectY, cursorX, cursorY) + 45) / 90f)) % 4; overrideLineRotation = true; } diff --git a/core/src/mindustry/io/LegacyMapIO.java b/core/src/mindustry/io/LegacyMapIO.java deleted file mode 100644 index d3f975e821..0000000000 --- a/core/src/mindustry/io/LegacyMapIO.java +++ /dev/null @@ -1,214 +0,0 @@ -package mindustry.io; - -import arc.struct.*; -import arc.files.*; -import arc.graphics.*; -import arc.util.*; -import arc.util.serialization.*; -import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.game.*; -import mindustry.io.MapIO.*; -import mindustry.maps.*; -import mindustry.world.*; -import mindustry.world.LegacyColorMapper.*; -import mindustry.world.blocks.*; - -import java.io.*; -import java.util.zip.*; - -import static mindustry.Vars.*; - -/** Map IO for the "old" .mmap format. - * Differentiate between legacy maps and new maps by checking the extension (or the header).*/ -public class LegacyMapIO{ - private static final ObjectMap fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad"); - private static final Json json = new Json(); - - /* Convert a map from the old format to the new format. */ - public static void convertMap(Fi in, Fi out) throws IOException{ - Map map = readMap(in, true); - - String waves = map.tags.get("waves", "[]"); - Array groups = new Array<>(json.fromJson(SpawnGroup[].class, waves)); - - Tile[][] tiles = world.createTiles(map.width, map.height); - for(int x = 0; x < map.width; x++){ - for(int y = 0; y < map.height; y++){ - tiles[x][y] = new CachedTile(); - tiles[x][y].x = (short)x; - tiles[x][y].y = (short)y; - } - } - state.rules.spawns = groups; - readTiles(map, tiles); - MapIO.writeMap(out, map); - } - - public static Map readMap(Fi file, boolean custom) throws IOException{ - try(DataInputStream stream = new DataInputStream(file.read(1024))){ - StringMap tags = new StringMap(); - - //meta is uncompressed - int version = stream.readInt(); - if(version != 1){ - throw new IOException("Outdated legacy map format"); - } - int build = stream.readInt(); - short width = stream.readShort(), height = stream.readShort(); - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - String name = stream.readUTF(); - String value = stream.readUTF(); - tags.put(name, value); - } - - return new Map(file, width, height, tags, custom, version, build); - } - } - - public static void readTiles(Map map, Tile[][] tiles) throws IOException{ - readTiles(map, (x, y) -> tiles[x][y]); - } - - public static void readTiles(Map map, TileProvider tiles) throws IOException{ - readTiles(map.file, map.width, map.height, tiles); - } - - private static void readTiles(Fi file, int width, int height, Tile[][] tiles) throws IOException{ - readTiles(file, width, height, (x, y) -> tiles[x][y]); - } - - private static void readTiles(Fi file, int width, int height, TileProvider tiles) throws IOException{ - try(BufferedInputStream input = file.read(bufferSize)){ - - //read map - { - DataInputStream stream = new DataInputStream(input); - - stream.readInt(); //version - stream.readInt(); //build - stream.readInt(); //width + height - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - stream.readUTF(); //key - stream.readUTF(); //val - } - } - - try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){ - - try{ - byte mapped = stream.readByte(); - IntMap idmap = new IntMap<>(); - IntMap namemap = new IntMap<>(); - - for(int i = 0; i < mapped; i++){ - byte type = stream.readByte(); - short total = stream.readShort(); - - for(int j = 0; j < total; j++){ - String name = stream.readUTF(); - if(type == 1){ - Block res = content.getByName(ContentType.block, fallback.get(name, name)); - idmap.put(j, res == null ? Blocks.air : res); - namemap.put(j, fallback.get(name, name)); - } - } - } - - //read floor and create tiles first - for(int i = 0; i < width * height; i++){ - int x = i % width, y = i / width; - int floorid = stream.readUnsignedByte(); - int oreid = stream.readUnsignedByte(); - int consecutives = stream.readUnsignedByte(); - - Tile tile = tiles.get(x, y); - tile.setFloor((Floor)idmap.get(floorid)); - tile.setOverlay(idmap.get(oreid)); - - for(int j = i + 1; j < i + 1 + consecutives; j++){ - int newx = j % width, newy = j / width; - Tile newTile = tiles.get(newx, newy); - newTile.setFloor((Floor)idmap.get(floorid)); - newTile.setOverlay(idmap.get(oreid)); - } - - i += consecutives; - } - - //read blocks - for(int i = 0; i < width * height; i++){ - int x = i % width, y = i / width; - int id = stream.readUnsignedByte(); - Block block = idmap.get(id); - if(block == null) block = Blocks.air; - - Tile tile = tiles.get(x, y); - //the spawn block is saved in the block tile layer in older maps, shift it to the overlay - if(block != Blocks.spawn){ - tile.setBlock(block); - }else{ - tile.setOverlay(block); - } - - if(namemap.get(id, "").equals("part")){ - stream.readByte(); //link - }else if(tile.entity != null){ - byte tr = stream.readByte(); - stream.readShort(); //read health (which is actually irrelevant) - - byte team = Pack.leftByte(tr); - byte rotation = Pack.rightByte(tr); - - tile.setTeam(Team.all[team]); - tile.entity.health = tile.block().health; - tile.rotation(rotation); - - if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){ - stream.readByte(); //these blocks have an extra config byte, read it - } - }else{ //no entity/part, read consecutives - int consecutives = stream.readUnsignedByte(); - - for(int j = i + 1; j < i + 1 + consecutives; j++){ - int newx = j % width, newy = j / width; - tiles.get(newx, newy).setBlock(block); - } - - i += consecutives; - } - } - - }finally{ - content.setTemporaryMapper(null); - } - } - } - } - - /** Reads a pixmap in the 3.5 pixmap format. */ - public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ - for(int x = 0; x < pixmap.getWidth(); x++){ - for(int y = 0; y < pixmap.getHeight(); y++){ - int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); - LegacyBlock block = LegacyColorMapper.get(color); - Tile tile = tiles[x][y]; - - tile.setFloor(block.floor); - tile.setBlock(block.wall); - if(block.ore != null) tile.setOverlay(block.ore); - - //place core - if(color == Color.rgba8888(Color.green)){ - //actual core parts - tile.setBlock(Blocks.coreShard); - tile.setTeam(Team.sharded); - } - } - } - } -} diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 07e9823569..d26adee127 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -10,6 +10,7 @@ import mindustry.core.*; import mindustry.game.*; import mindustry.maps.*; import mindustry.world.*; +import mindustry.world.LegacyColorMapper.*; import mindustry.world.blocks.storage.*; import java.io.*; @@ -91,7 +92,7 @@ public class MapIO{ public void setTeam(Team team){ super.setTeam(team); if(block instanceof CoreBlock){ - map.teams.add((int) team.id); + map.teams.add((int)team.id); } } }; @@ -150,6 +151,28 @@ public class MapIO{ return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color); } + /** Reads a pixmap in the 3.5 pixmap format. */ + public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ + for(int x = 0; x < pixmap.getWidth(); x++){ + for(int y = 0; y < pixmap.getHeight(); y++){ + int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); + LegacyBlock block = LegacyColorMapper.get(color); + Tile tile = tiles[x][y]; + + tile.setFloor(block.floor); + tile.setBlock(block.wall); + if(block.ore != null) tile.setOverlay(block.ore); + + //place core + if(color == Color.rgba8888(Color.green)){ + //actual core parts + tile.setBlock(Blocks.coreShard); + tile.setTeam(Team.sharded); + } + } + } + } + interface TileProvider{ Tile get(int x, int y); } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index f3fdc0c20e..1d4ab19859 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -217,7 +217,7 @@ public abstract class SaveVersion extends SaveFileReader{ Array data = state.teams.getActive(); stream.writeInt(data.size); for(TeamData team : data){ - stream.writeInt((int) team.team.id); + stream.writeInt((int)team.team.id); stream.writeInt(team.brokenBlocks.size); for(BrokenBlock block : team.brokenBlocks){ stream.writeShort(block.x); @@ -258,7 +258,7 @@ public abstract class SaveVersion extends SaveFileReader{ public void readEntities(DataInput stream) throws IOException{ int teamc = stream.readInt(); for(int i = 0; i < teamc; i++){ - Team team = Team.all[stream.readInt()]; + Team team = Team.get(stream.readInt()); TeamData data = state.teams.get(team); int blocks = stream.readInt(); for(int j = 0; j < blocks; j++){ diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index de0faaa372..5095ce396a 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -87,7 +87,7 @@ public class TypeIO{ @WriteClass(BaseUnit.class) public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){ - buffer.put((byte) (int) unit.getTeam().id); + buffer.put((byte) (int)unit.getTeam().id); buffer.putInt(unit.getID()); } @@ -95,7 +95,7 @@ public class TypeIO{ public static BaseUnit readBaseUnit(ByteBuffer buffer){ byte tid = buffer.get(); int id = buffer.getInt(); - return unitGroups[tid].getByID(id); + return unitGroup.getByID(id); } @WriteClass(Tile.class) @@ -194,12 +194,12 @@ public class TypeIO{ @WriteClass(Team.class) public static void writeTeam(ByteBuffer buffer, Team reason){ - buffer.put((byte) (int) reason.id); + buffer.put((byte) (int)reason.id); } @ReadClass(Team.class) public static Team readTeam(ByteBuffer buffer){ - return Team.all[buffer.get()]; + return Team.get(buffer.get()); } @WriteClass(UnitCommand.class) diff --git a/core/src/mindustry/maps/generators/MapGenerator.java b/core/src/mindustry/maps/generators/MapGenerator.java index c0083c4738..69c11bdc7b 100644 --- a/core/src/mindustry/maps/generators/MapGenerator.java +++ b/core/src/mindustry/maps/generators/MapGenerator.java @@ -74,7 +74,7 @@ public class MapGenerator extends Generator{ for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ - if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == defaultTeam){ + if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == state.rules.defaultTeam){ players.add(new Point2(x, y)); tiles[x][y].setBlock(Blocks.air); } diff --git a/core/src/mindustry/ui/ItemsDisplay.java b/core/src/mindustry/ui/ItemsDisplay.java index 432417b305..755590f34f 100644 --- a/core/src/mindustry/ui/ItemsDisplay.java +++ b/core/src/mindustry/ui/ItemsDisplay.java @@ -39,9 +39,9 @@ public class ItemsDisplay extends Table{ private String format(Item item){ builder.setLength(0); builder.append(ui.formatAmount(data.items().get(item, 0))); - if(!state.is(State.menu) && !state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity != null && state.teams.get(player.getTeam()).cores.first().entity.items.get(item) > 0){ + if(!state.is(State.menu) && state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().items.get(item) > 0){ builder.append(" [unlaunched]+ "); - builder.append(ui.formatAmount(state.teams.get(player.getTeam()).cores.first().entity.items.get(item))); + builder.append(ui.formatAmount(state.teams.get(player.getTeam()).core().items.get(item))); } return builder.toString(); } diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index c2ca5b25e5..688923924c 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -168,7 +168,7 @@ public class HudFragment extends Fragment{ t.table(teams -> { teams.left(); int i = 0; - for(Team team : Team.all){ + for(Team team : Team.base()){ ImageButton button = teams.addImageButton(Tex.whiteui, Styles.clearTogglePartiali, 40f, () -> Call.setPlayerTeamEditor(player, team)) .size(50f).margin(6f).get(); button.getImageCell().grow(); @@ -287,7 +287,7 @@ public class HudFragment extends Fragment{ }); t.top().visible(() -> { - if(state.is(State.menu) || state.teams.get(player.getTeam()).cores.size == 0 || state.teams.get(player.getTeam()).cores.first().entity == null){ + if(state.is(State.menu) || !state.teams.get(player.getTeam()).hasCore()){ coreAttackTime[0] = 0f; return false; } @@ -628,7 +628,7 @@ public class HudFragment extends Fragment{ } if(state.rules.waveTimer){ - builder.append((state.rules.waitForWaveToEnd && unitGroups[(int) waveTeam.id].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))); + builder.append((state.rules.waitForWaveToEnd && state.enemies > 0 ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60))))); }else if(state.enemies == 0){ builder.append(Core.bundle.get("waiting")); } diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index df0d9f7269..a9cca9fb85 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -8,6 +8,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.core.GameState.*; +import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; @@ -65,7 +66,7 @@ public class PlayerListFragment extends Fragment{ float h = 74f; - playerGroup.all().sort((p1, p2) -> p1.getTeam().compareTo(p2.getTeam())); + playerGroup.all().sort(Structs.comparing(Unit::getTeam)); playerGroup.all().each(user -> { NetConnection connection = user.con; diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index dafd9fe38d..f101068cf0 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -38,7 +38,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(previous.size); - world.setBlock(tile, sub, team, rotation); + tile.set(sub, team, rotation); tile.ent().setDeconstruct(previous); tile.entity.health = tile.entity.maxHealth() * prevPercent; @@ -60,7 +60,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(result.size); - world.setBlock(tile, sub, team, rotation); + tile.set(sub, team, rotation); tile.ent().setConstruct(previous, result); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false))); @@ -72,7 +72,7 @@ public class Build{ return false; } - if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == waveTeam)){ + if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == state.rules.waveTeam)){ return false; } @@ -80,13 +80,8 @@ public class Build{ return false; } - //check for enemy cores - for(Team enemy : state.teams.enemiesOf(team)){ - for(Tile core : state.teams.get(enemy).cores){ - if(Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.drawx(), core.drawy()) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f){ - return false; - } - } + if(!state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ + return false; } Tile tile = world.tile(x, y); diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java index e46a57d3ba..281828dcd7 100644 --- a/core/src/mindustry/world/CachedTile.java +++ b/core/src/mindustry/world/CachedTile.java @@ -16,7 +16,7 @@ public class CachedTile extends Tile{ @Override public Team getTeam(){ - return Team.all[getTeamID()]; + return Team.get(getTeamID()); } @Override diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index a1fb5fa9ff..4a8b2fa629 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -142,11 +142,11 @@ public class Tile implements Position, TargetTrait{ @Override public Team getTeam(){ - return Team.all[link().team]; + return Team.get(link().team); } public void setTeam(Team team){ - this.team = (byte) (int) team.id; + this.team = (byte) (int)team.id; } public byte getTeamID(){ @@ -156,7 +156,7 @@ public class Tile implements Position, TargetTrait{ public void setBlock(@NonNull Block type, Team team, int rotation){ preChanged(); this.block = type; - this.team = (byte) (int) team.id; + this.team = (byte) (int)team.id; this.rotation = (byte)Mathf.mod(rotation, 4); changed(); } @@ -186,6 +186,35 @@ public class Tile implements Position, TargetTrait{ setOverlay(overlay); } + public void remove(){ + link().getLinkedTiles(other -> other.setBlock(Blocks.air)); + } + + public void set(Block block, Team team){ + set(block, team, 0); + } + + public void set(Block block, Team team, int rotation){ + setBlock(block, team, rotation); + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; + if(!(worldx == x && worldy == y)){ + Tile toplace = world.tile(worldx, worldy); + if(toplace != null){ + toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); + } + } + } + } + } + } + public byte rotation(){ return rotation; } @@ -240,7 +269,7 @@ public class Tile implements Position, TargetTrait{ } public boolean isEnemyCheat(){ - return getTeam() == waveTeam && state.rules.enemyCheat; + return getTeam() == state.rules.waveTeam && state.rules.enemyCheat; } public boolean isLinked(){ @@ -344,7 +373,7 @@ public class Tile implements Position, TargetTrait{ } public boolean interactable(Team team){ - return getTeam() == Team.derelict || team == getTeam(); + return state.teams.canInteract(team, getTeam()); } public Item drop(){ diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 69d9ba61e8..df90a969b7 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -66,7 +66,7 @@ public class BuildBlock extends Block{ public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ if(tile == null) return; float healthf = tile.entity == null ? 1f : tile.entity.healthf(); - world.setBlock(tile, block, team, rotation); + tile.set(block, team, rotation); if(tile.entity != null){ tile.entity.health = block.health * healthf; } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 7c766fd1d3..f9a5cf6c9b 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -84,12 +84,12 @@ public class CoreBlock extends StorageBlock{ public void onProximityUpdate(Tile tile){ CoreEntity entity = tile.ent(); - for(Tile other : state.teams.get(tile.getTeam()).cores){ - if(other != tile){ - entity.items = other.entity.items; + for(TileEntity other : state.teams.cores(tile.getTeam())){ + if(other.tile != tile){ + entity.items = other.items; } } - state.teams.get(tile.getTeam()).cores.add(tile); + state.teams.registerCore(entity); entity.storageCapacity = itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); entity.proximity().each(this::isContainer, t -> { @@ -97,9 +97,9 @@ public class CoreBlock extends StorageBlock{ t.ent().linkedCore = tile; }); - for(Tile other : state.teams.get(tile.getTeam()).cores){ - if(other == tile) continue; - entity.storageCapacity += other.block().itemCapacity + other.entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); + for(TileEntity other : state.teams.cores(tile.getTeam())){ + if(other.tile == tile) continue; + entity.storageCapacity += other.block.itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); } if(!world.isGenerating()){ @@ -108,9 +108,8 @@ public class CoreBlock extends StorageBlock{ } } - for(Tile other : state.teams.get(tile.getTeam()).cores){ - CoreEntity oe = other.ent(); - oe.storageCapacity = entity.storageCapacity; + for(CoreEntity other : state.teams.cores(tile.getTeam())){ + other.storageCapacity = entity.storageCapacity; } } @@ -151,8 +150,9 @@ public class CoreBlock extends StorageBlock{ @Override public void removed(Tile tile){ + CoreEntity entity = tile.ent(); int total = tile.entity.proximity().count(e -> e.entity.items == tile.entity.items); - float fract = 1f / total / state.teams.get(tile.getTeam()).cores.size; + float fract = 1f / total / state.teams.cores(tile.getTeam()).size; tile.entity.proximity().each(e -> isContainer(e) && e.entity.items == tile.entity.items, t -> { StorageBlockEntity ent = (StorageBlockEntity)t.entity; @@ -163,22 +163,23 @@ public class CoreBlock extends StorageBlock{ } }); - state.teams.get(tile.getTeam()).cores.remove(tile); + state.teams.unregisterCore(entity); - int max = itemCapacity * state.teams.get(tile.getTeam()).cores.size; + int max = itemCapacity * state.teams.cores(tile.getTeam()).size; for(Item item : content.items()){ tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max)); } - for(Tile other : state.teams.get(tile.getTeam()).cores){ - other.block().onProximityUpdate(other); + for(CoreEntity other : state.teams.cores(tile.getTeam())){ + other.block.onProximityUpdate(other.tile); } } @Override public void placed(Tile tile){ super.placed(tile); - state.teams.get(tile.getTeam()).cores.add(tile); + CoreEntity entity = tile.ent(); + state.teams.registerCore(entity); } @Override diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index 9dae2923d3..0d2e0428de 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -58,7 +58,7 @@ public class CommandCenter extends Block{ ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); if(set.size == 1){ - for(BaseUnit unit : unitGroups[(int) tile.getTeam().id].all()){ + for(BaseUnit unit : unitGroups[(int)tile.getTeam().id].all()){ unit.onCommand(UnitCommand.all[0]); } } @@ -116,7 +116,7 @@ public class CommandCenter extends Block{ Team team = (player == null ? tile.getTeam() : player.getTeam()); - for(BaseUnit unit : unitGroups[(int) team.id].all()){ + for(BaseUnit unit : unitGroups[(int)team.id].all()){ unit.onCommand(command); } diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index 984fa9e985..bdbb86ad5e 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -55,13 +55,13 @@ public class SStats implements SteamUserStatsCallback{ private void checkUpdate(){ if(campaign()){ - SStat.maxUnitActive.max(unitGroups[(int) player.getTeam().id].size()); + SStat.maxUnitActive.max(unitGroups[(int)player.getTeam().id].size()); - if(unitGroups[(int) player.getTeam().id].count(u -> u.getType() == UnitTypes.phantom) >= 10){ + if(unitGroups[(int)player.getTeam().id].count(u -> u.getType() == UnitTypes.phantom) >= 10){ active10Phantoms.complete(); } - if(unitGroups[(int) player.getTeam().id].count(u -> u.getType() == UnitTypes.crawler) >= 50){ + if(unitGroups[(int)player.getTeam().id].count(u -> u.getType() == UnitTypes.crawler) >= 50){ active50Crawlers.complete(); } diff --git a/gradle.properties b/gradle.properties index 29c1e50fad..e28d4db59a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=88c1a9afe2f5be4dd06e47ac8afe070247b3da29 +archash=447f3bb0e4616f82680f3234ad4e0cce48880884 diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 8ff1874407..109552adb4 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -292,7 +292,7 @@ public class ServerControl implements ApplicationListener{ info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave); if(state.rules.waves){ - info("&ly {0} enemies.", unitGroups[(int) Team.crux.id].size()); + info("&ly {0} enemies.", unitGroups[(int)Team.crux.id].size()); }else{ info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60)); } @@ -421,14 +421,14 @@ public class ServerControl implements ApplicationListener{ try{ Team team = arg.length == 0 ? Team.sharded : Team.valueOf(arg[0]); - if(state.teams.get(team).cores.isEmpty()){ + if(state.teams.cores(team).isEmpty()){ err("That team has no cores."); return; } for(Item item : content.items()){ if(item.type == ItemType.material){ - state.teams.get(team).cores.first().entity.items.set(item, state.teams.get(team).cores.first().block().itemCapacity); + state.teams.cores(team).first().entity.items.set(item, state.teams.cores(team).first().block().itemCapacity); } } diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 43c819bdfd..722bf246d0 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -106,8 +106,8 @@ public class ApplicationTests{ Time.update(); Time.update(); Time.setDeltaProvider(() -> 1f); - unitGroups[(int) waveTeam.id].updateEvents(); - assertFalse(unitGroups[(int) waveTeam.id].isEmpty(), "No enemies spawned."); + unitGroup.update(); + assertFalse(unitGroup.isEmpty(), "No enemies spawned."); } @Test @@ -128,7 +128,7 @@ public class ApplicationTests{ createMap(); int bx = 4; int by = 4; - world.setBlock(world.tile(bx, by), Blocks.coreShard, Team.sharded); + world.tile(bx, by).set(Blocks.coreShard, Team.sharded); assertEquals(world.tile(bx, by).getTeam(), Team.sharded); for(int x = bx - 1; x <= bx + 1; x++){ for(int y = by - 1; y <= by + 1; y++){ @@ -198,7 +198,7 @@ public class ApplicationTests{ @Test void save(){ world.loadMap(testMap); - assertTrue(state.teams.get(defaultTeam).cores.size > 0); + assertTrue(state.teams.playerCores().size > 0); SaveIO.save(saveDirectory.child("0.msav")); } @@ -213,7 +213,7 @@ public class ApplicationTests{ assertEquals(world.width(), map.width); assertEquals(world.height(), map.height); - assertTrue(state.teams.get(defaultTeam).cores.size > 0); + assertTrue(state.teams.playerCores().size > 0); } @Test @@ -379,12 +379,12 @@ public class ApplicationTests{ createMap(); Tile core = world.tile(5, 5); - world.setBlock(core, Blocks.coreShard, Team.sharded); + core.set(Blocks.coreShard, Team.sharded); for(Item item : content.items()){ core.entity.items.set(item, 3000); } - assertEquals(core, state.teams.get(Team.sharded).cores.first()); + assertEquals(core.entity, state.teams.get(Team.sharded).core()); } void depositTest(Block block, Item item){ diff --git a/tests/src/test/java/ZoneTests.java b/tests/src/test/java/ZoneTests.java index 2a044d5b75..a238a815ee 100644 --- a/tests/src/test/java/ZoneTests.java +++ b/tests/src/test/java/ZoneTests.java @@ -52,7 +52,7 @@ public class ZoneTests{ if(tile.drop() != null){ resources.add(tile.drop()); } - if(tile.block() instanceof CoreBlock && tile.getTeam() == defaultTeam){ + if(tile.block() instanceof CoreBlock && tile.getTeam() == state.rules.defaultTeam){ hasSpawnPoint = true; } } @@ -69,7 +69,7 @@ public class ZoneTests{ } assertTrue(hasSpawnPoint, "Zone \"" + zone.name + "\" has no spawn points."); - assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && !state.teams.get(waveTeam).cores.isEmpty()), "Zone \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); + assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && state.teams.get(state.rules.waveTeam).hasCore()), "Zone \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); for(Item item : resources){ assertTrue(zone.resources.contains(item), "Zone \"" + zone.name + "\" is missing item in resource list: \"" + item.name + "\""); diff --git a/tools/build.gradle b/tools/build.gradle index ea158a66a1..033040e96d 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -240,7 +240,7 @@ task swapColors(){ Color.argb8888ToColor(tmpc, c) if(tmpc.a < 0.1f) continue if(map.containsKey(c)){ - img.setRGB(x, y, (int) map.get(c)) + img.setRGB(x, y, (int)map.get(c)) } } }