diff --git a/core/assets/maps/saltFlats.msav b/core/assets/maps/saltFlats.msav index c982e27d4e..a0688e922d 100644 Binary files a/core/assets/maps/saltFlats.msav and b/core/assets/maps/saltFlats.msav differ diff --git a/core/src/io/anuke/mindustry/content/Fx.java b/core/src/io/anuke/mindustry/content/Fx.java index 3846f8afbf..681340e4e9 100644 --- a/core/src/io/anuke/mindustry/content/Fx.java +++ b/core/src/io/anuke/mindustry/content/Fx.java @@ -792,8 +792,9 @@ public class Fx implements ContentList{ Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); for(int i : Mathf.signs){ + float ex = e.x, ey = e.y, fout = e.fout(); Angles.randLenVectors(e.id, 4, 1f + e.finpow() * 11f, e.rotation + 90f * i, 20f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f); + Fill.circle(ex + x, ey + y, fout * 1.5f); }); } @@ -816,8 +817,9 @@ public class Fx implements ContentList{ Draw.color(Color.LIGHT_GRAY); for(int i : Mathf.signs){ + float ex = e.x, ey = e.y, fout = e.fout(); Angles.randLenVectors(e.id, 4, -e.finpow() * 15f, e.rotation + 90f * i, 25f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 2f); + Fill.circle(ex + x, ey + y, fout * 2f); }); } diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 3d5901dc97..c6eddd548f 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -61,7 +61,7 @@ public class Logic implements ApplicationListener{ } TeamData data = state.teams.get(tile.getTeam()); - data.brokenBlocks.addFirst(BrokenBlock.get(tile.x, tile.y, block.id, tile.rotation())); + data.brokenBlocks.addFirst(BrokenBlock.get(tile.x, tile.y, tile.rotation(), block.id)); }); } diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 658afabd2c..dab0c9b31b 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -360,11 +360,11 @@ public class NetClient implements ApplicationListener{ if(timer.get(0, playerSyncTime)){ BuildRequest[] requests; //limit to 10 to prevent buffer overflows - int usedRequests = Math.min(player.getPlaceQueue().size, 10); + int usedRequests = Math.min(player.buildQueue().size, 10); requests = new BuildRequest[usedRequests]; for(int i = 0; i < usedRequests; i++){ - requests[i] = player.getPlaceQueue().get(i); + requests[i] = player.buildQueue().get(i); } Call.onClientShapshot(lastSent++, player.x, player.y, diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 7da3a47a24..ab4eca7e0d 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -282,7 +282,7 @@ public class NetServer implements ApplicationListener{ player.isTyping = chatting; player.isBoosting = boosting; player.isShooting = shooting; - player.getPlaceQueue().clear(); + player.buildQueue().clear(); for(BuildRequest req : requests){ Tile tile = world.tile(req.x, req.y); if(tile == null) continue; @@ -292,7 +292,7 @@ public class NetServer implements ApplicationListener{ }else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){ continue; } - player.getPlaceQueue().addLast(req); + player.buildQueue().addLast(req); } vector.set(x - player.getInterpolator().target.x, y - player.getInterpolator().target.y); diff --git a/core/src/io/anuke/mindustry/entities/Entities.java b/core/src/io/anuke/mindustry/entities/Entities.java index d0d5d16dea..2a6f388ff5 100755 --- a/core/src/io/anuke/mindustry/entities/Entities.java +++ b/core/src/io/anuke/mindustry/entities/Entities.java @@ -13,7 +13,6 @@ import io.anuke.mindustry.entities.traits.Entity; import static io.anuke.mindustry.Vars.collisions; public class Entities{ - public static final int maxLeafObjects = 4; private static final Array> groupArray = new Array<>(); private static final IntMap> groups = new IntMap<>(); private static final Rectangle viewport = new Rectangle(); diff --git a/core/src/io/anuke/mindustry/entities/EntityGroup.java b/core/src/io/anuke/mindustry/entities/EntityGroup.java index 314aa63d76..d3010c84f3 100644 --- a/core/src/io/anuke/mindustry/entities/EntityGroup.java +++ b/core/src/io/anuke/mindustry/entities/EntityGroup.java @@ -17,7 +17,7 @@ public class EntityGroup{ private final Array entitiesToRemove = new Array<>(false, 16); private final Array entitiesToAdd = new Array<>(false, 16); private IntMap map; - private QuadTree tree; + private QuadTree tree; private Consumer removeListener; private Consumer addListener; @@ -27,7 +27,7 @@ public class EntityGroup{ this.type = type; if(useTree){ - tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(0, 0, 0, 0)); + tree = new QuadTree<>(new Rectangle(0, 0, 0, 0)); } } @@ -124,7 +124,7 @@ public class EntityGroup{ /** Resizes the internal quadtree, if it is enabled.*/ public void resize(float x, float y, float w, float h){ if(useTree){ - tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(x, y, w, h)); + tree = new QuadTree<>(new Rectangle(x, y, w, h)); } } diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderMinerTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderMinerTrait.java index 253e5c41d0..5fbde29251 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderMinerTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderMinerTrait.java @@ -7,7 +7,7 @@ public interface BuilderMinerTrait extends MinerTrait, BuilderTrait{ updateBuilding(); //mine only when not building - if(getCurrentRequest() == null){ + if(buildRequest() == null){ updateMining(); } } diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index 45cb67da96..27361d61d5 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -35,21 +35,21 @@ public interface BuilderTrait extends Entity, TeamTrait{ Unit unit = (Unit)this; //remove already completed build requests removal.clear(); - for(BuildRequest req : getPlaceQueue()){ + for(BuildRequest req : buildQueue()){ removal.add(req); } - getPlaceQueue().clear(); + buildQueue().clear(); for(BuildRequest request : removal){ if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) || (!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate) && world.tile(request.x, request.y).block() == request.block))){ - getPlaceQueue().addLast(request); + buildQueue().addLast(request); } } - BuildRequest current = getCurrentRequest(); + BuildRequest current = buildRequest(); if(current == null){ return; @@ -58,9 +58,9 @@ public interface BuilderTrait extends Entity, TeamTrait{ Tile tile = world.tile(current.x, current.y); if(dst(tile) > finalPlaceDst){ - if(getPlaceQueue().size > 1){ - getPlaceQueue().removeFirst(); - getPlaceQueue().addLast(current); + if(buildQueue().size > 1){ + buildQueue().removeFirst(); + buildQueue().addLast(current); } return; } @@ -71,7 +71,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ }else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){ Call.beginBreak(getTeam(), current.x, current.y); }else{ - getPlaceQueue().removeFirst(); + buildQueue().removeFirst(); return; } } @@ -115,7 +115,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ } /** Returns the queue for storing build requests. */ - Queue getPlaceQueue(); + Queue buildQueue(); /** Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all. */ float getBuildPower(Tile tile); @@ -126,7 +126,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ } default void writeBuilding(DataOutput output) throws IOException{ - BuildRequest request = getCurrentRequest(); + BuildRequest request = buildRequest(); if(request != null){ output.writeByte(request.breaking ? 1 : 0); @@ -146,7 +146,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ } default void readBuilding(DataInput input, boolean applyChanges) throws IOException{ - if(applyChanges) getPlaceQueue().clear(); + if(applyChanges) buildQueue().clear(); byte type = input.readByte(); if(type != -1){ @@ -165,26 +165,26 @@ public interface BuilderTrait extends Entity, TeamTrait{ request.progress = progress; if(applyChanges){ - getPlaceQueue().addLast(request); + buildQueue().addLast(request); }else if(isBuilding()){ - getCurrentRequest().progress = progress; + buildRequest().progress = progress; } } } /** Return whether this builder's place queue contains items. */ default boolean isBuilding(){ - return getPlaceQueue().size != 0; + return buildQueue().size != 0; } /** Clears the placement queue. */ default void clearBuilding(){ - getPlaceQueue().clear(); + buildQueue().clear(); } /** Add another build requests to the tail of the queue, if it doesn't exist there yet. */ default void addBuildRequest(BuildRequest place){ - for(BuildRequest request : getPlaceQueue()){ + for(BuildRequest request : buildQueue()){ if(request.x == place.x && request.y == place.y){ return; } @@ -193,15 +193,15 @@ public interface BuilderTrait extends Entity, TeamTrait{ if(tile != null && tile.entity instanceof BuildEntity){ place.progress = tile.entity().progress; } - getPlaceQueue().addLast(place); + buildQueue().addLast(place); } /** * Return the build requests currently active, or the one at the top of the queue. * May return null. */ - default BuildRequest getCurrentRequest(){ - return getPlaceQueue().size == 0 ? null : getPlaceQueue().first(); + default BuildRequest buildRequest(){ + return buildQueue().size == 0 ? null : buildQueue().first(); } //due to iOS weirdness, this is apparently required @@ -215,7 +215,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ if(!isBuilding()) return; Unit unit = (Unit)this; - BuildRequest request = getCurrentRequest(); + BuildRequest request = buildRequest(); Tile tile = world.tile(request.x, request.y); if(dst(tile) > placeDistance && !state.isEditor()){ diff --git a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java index 440cab7a2b..de040681cc 100644 --- a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java @@ -112,10 +112,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ this.state.set(state); } - public void retarget(Runnable run){ - if(timer.get(timerTarget, 20)){ - run.run(); - } + public boolean retarget(){ + return timer.get(timerTarget, 20); } /** Only runs when the unit has a target. */ diff --git a/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java b/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java index dc92379241..e0a95b7866 100644 --- a/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java @@ -32,7 +32,7 @@ public abstract class FlyingUnit extends BaseUnit{ target = null; } - retarget(() -> { + if(retarget()){ targetClosest(); if(target == null) targetClosestEnemyFlag(BlockFlag.producer); @@ -41,7 +41,7 @@ public abstract class FlyingUnit extends BaseUnit{ if(target == null){ setState(patrol); } - }); + }; if(target != null){ attack(type.attackLength); @@ -71,7 +71,7 @@ public abstract class FlyingUnit extends BaseUnit{ }, patrol = new UnitState(){ public void update(){ - retarget(() -> { + if(retarget()){ targetClosest(); targetClosestEnemyFlag(BlockFlag.target); @@ -81,7 +81,7 @@ public abstract class FlyingUnit extends BaseUnit{ } target = getClosestCore(); - }); + }; if(target != null){ circle(60f + Mathf.absin(Time.time() + Mathf.randomSeed(id) * 1200f, 70f, 1200f)); diff --git a/core/src/io/anuke/mindustry/entities/type/GroundUnit.java b/core/src/io/anuke/mindustry/entities/type/GroundUnit.java index 0239f9bdf2..e319063e9d 100644 --- a/core/src/io/anuke/mindustry/entities/type/GroundUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/GroundUnit.java @@ -176,7 +176,9 @@ public abstract class GroundUnit extends BaseUnit{ target = null; } - retarget(this::targetClosest); + if(retarget()){ + targetClosest(); + } } protected void patrol(){ diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 9389b2d95e..3f1cf60d6d 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -241,7 +241,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } @Override - public Queue getPlaceQueue(){ + public Queue buildQueue(){ return placeQueue; } @@ -428,8 +428,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ /** Draw all current build requests. Does not draw the beam effect, only the positions. */ public void drawBuildRequests(){ BuildRequest last = null; - for(BuildRequest request : getPlaceQueue()){ - if(request.progress > 0.01f || (getCurrentRequest() == request && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue; + for(BuildRequest request : buildQueue()){ + if(request.progress > 0.01f || (buildRequest() == request && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue; if(request.breaking){ Block block = world.ltile(request.x, request.y).block(); diff --git a/core/src/io/anuke/mindustry/entities/type/base/BaseDrone.java b/core/src/io/anuke/mindustry/entities/type/base/BaseDrone.java index f0bba823af..27ac0c86ff 100644 --- a/core/src/io/anuke/mindustry/entities/type/base/BaseDrone.java +++ b/core/src/io/anuke/mindustry/entities/type/base/BaseDrone.java @@ -19,14 +19,14 @@ public abstract class BaseDrone extends FlyingUnit{ if(health >= maxHealth()){ state.set(attack); }else if(!targetHasFlag(BlockFlag.repair)){ - retarget(() -> { + if(retarget()){ Tile repairPoint = Geometry.findClosest(x, y, world.indexer.getAllied(team, BlockFlag.repair)); if(repairPoint != null){ target = repairPoint; }else{ setState(getStartState()); } - }); + } }else{ circle(40f); } diff --git a/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java b/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java index 2477128a88..4b75d6e734 100644 --- a/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java @@ -6,12 +6,15 @@ import io.anuke.arc.collection.IntIntMap; import io.anuke.arc.collection.Queue; import io.anuke.arc.math.Mathf; import io.anuke.arc.util.*; +import io.anuke.mindustry.Vars; import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.traits.BuilderTrait; import io.anuke.mindustry.entities.traits.TargetTrait; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.units.UnitState; import io.anuke.mindustry.game.EventType.BuildSelectEvent; +import io.anuke.mindustry.game.Teams.TeamData; +import io.anuke.mindustry.gen.BrokenBlock; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.BuildBlock; import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; @@ -20,7 +23,6 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; -//TODO follow players public class BuilderDrone extends BaseDrone implements BuilderTrait{ private static final StaticReset reset = new StaticReset(); private static final IntIntMap totals = new IntIntMap(); @@ -43,12 +45,22 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ BuildEntity entity = (BuildEntity)target; TileEntity core = getClosestCore(); - if(entity != null && core != null && (entity.progress < 1f || entity.progress > 0f) && entity.tile.block() instanceof BuildBlock){ //building is valid + if(isBuilding() && entity == null && isRebuild()){ + target = world.tile(buildRequest().x, buildRequest().y); + circle(placeDistance * 0.7f); + target = null; + + BuildRequest request = buildRequest(); + + if(world.tile(request.x, request.y).entity instanceof BuildEntity){ + target = world.tile(request.x, request.y).entity; + } + }else if(entity != null && core != null && (entity.progress < 1f || entity.progress > 0f) && entity.tile.block() instanceof BuildBlock){ //building is valid if(!isBuilding() && dst(target) < placeDistance * 0.9f){ //within distance, begin placing if(isBreaking){ - getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y)); + buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y)); }else{ - getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock)); + buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock)); } } @@ -58,7 +70,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ if(playerTarget == null || playerTarget.getTeam() != team || !playerTarget.isValid()){ playerTarget = null; - retarget(() -> { + if(retarget()){ float minDst = Float.POSITIVE_INFINITY; int minDrones = Integer.MAX_VALUE; @@ -75,7 +87,13 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ } } } - }); + } + + if(getSpawner() != null){ + target = getSpawner(); + circle(40f); + target = null; + } }else{ incDrones(playerTarget); TargetTrait prev = target; @@ -103,7 +121,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ BuilderDrone drone = (BuilderDrone)unit; if(drone.isBuilding()){ //stop building if opposite building begins. - BuildRequest req = drone.getCurrentRequest(); + BuildRequest req = drone.buildRequest(); if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){ drone.clearBuilding(); drone.target = null; @@ -131,13 +149,17 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ } } + boolean isRebuild(){ + return Vars.state.rules.enemyCheat && team == waveTeam; + } + @Override public float getBuildPower(Tile tile){ return type.buildPower; } @Override - public Queue getPlaceQueue(){ + public Queue buildQueue(){ return placeQueue; } @@ -147,8 +169,8 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ if(!isBuilding() && timer.get(timerTarget2, 15)){ for(Player player : playerGroup.all()){ - if(player.getTeam() == team && player.getCurrentRequest() != null){ - BuildRequest req = player.getCurrentRequest(); + if(player.getTeam() == team && player.buildRequest() != null){ + BuildRequest req = player.buildRequest(); Tile tile = world.tile(req.x, req.y); if(tile != null && tile.entity instanceof BuildEntity){ BuildEntity b = tile.entity(); @@ -162,6 +184,16 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ } } } + + if(isRebuild()){ + TeamData data = Vars.state.teams.get(team); + if(!data.brokenBlocks.isEmpty()){ + long block = data.brokenBlocks.removeLast(); + + placeQueue.addFirst(new BuildRequest(BrokenBlock.x(block), BrokenBlock.y(block), BrokenBlock.rotation(block), content.block(BrokenBlock.block(block)))); + setState(build); + } + } } updateBuilding(); diff --git a/core/src/io/anuke/mindustry/entities/type/base/MinerDrone.java b/core/src/io/anuke/mindustry/entities/type/base/MinerDrone.java index 605bebb148..9cc5f4f31c 100644 --- a/core/src/io/anuke/mindustry/entities/type/base/MinerDrone.java +++ b/core/src/io/anuke/mindustry/entities/type/base/MinerDrone.java @@ -52,13 +52,13 @@ public class MinerDrone extends BaseDrone implements MinerTrait{ return; } - retarget(() -> { + if(retarget()){ findItem(); if(targetItem == null) return; target = world.indexer.findClosestOre(x, y, targetItem); - }); + }; if(target instanceof Tile){ moveTo(type.range / 1.5f); diff --git a/core/src/io/anuke/mindustry/entities/type/base/RepairDrone.java b/core/src/io/anuke/mindustry/entities/type/base/RepairDrone.java index 9375e6ca8e..e5be4d3d07 100644 --- a/core/src/io/anuke/mindustry/entities/type/base/RepairDrone.java +++ b/core/src/io/anuke/mindustry/entities/type/base/RepairDrone.java @@ -19,7 +19,9 @@ public class RepairDrone extends BaseDrone{ public void update(){ - retarget(() -> target = Units.findDamagedTile(team, x, y)); + if(retarget()){ + target = Units.findDamagedTile(team, x, y); + } if(target != null){ if(target.dst(RepairDrone.this) > type.range){ diff --git a/core/src/io/anuke/mindustry/game/Teams.java b/core/src/io/anuke/mindustry/game/Teams.java index 077729ddd0..be4d1a7e2c 100644 --- a/core/src/io/anuke/mindustry/game/Teams.java +++ b/core/src/io/anuke/mindustry/game/Teams.java @@ -42,11 +42,17 @@ public class Teams{ return enemiesOf(team).contains(other); } - public class TeamData{ + /** 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 static class TeamData{ public final ObjectSet cores = new ObjectSet<>(); - public final LongQueue brokenBlocks = new LongQueue(); public final EnumSet enemies; public final Team team; + public LongQueue brokenBlocks = new LongQueue(); public TeamData(Team team, EnumSet enemies){ this.team = team; diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 2198f002ef..ebac7e421e 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -214,7 +214,7 @@ public class DesktopInput extends InputHandler{ mode = placing; }else if(selected != null){ //only begin shooting if there's no cursor event - if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.getPlaceQueue().size == 0 && !droppingItem && + if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.buildQueue().size == 0 && !droppingItem && !tryBeginMine(selected) && player.getMineTile() == null && !ui.chatfrag.chatOpen()){ player.isShooting = true; } @@ -222,7 +222,7 @@ public class DesktopInput extends InputHandler{ player.isShooting = true; } }else if(Core.input.keyTap(Binding.deselect) && (block != null || mode != none || player.isBuilding()) && - !(player.getCurrentRequest() != null && player.getCurrentRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){ + !(player.buildRequest() != null && player.buildRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){ if(block == null){ player.clearBuilding(); } diff --git a/core/src/io/anuke/mindustry/io/JsonIO.java b/core/src/io/anuke/mindustry/io/JsonIO.java index 3c1ce9520c..6cee4ca311 100644 --- a/core/src/io/anuke/mindustry/io/JsonIO.java +++ b/core/src/io/anuke/mindustry/io/JsonIO.java @@ -1,10 +1,12 @@ package io.anuke.mindustry.io; +import io.anuke.arc.collection.EnumSet; +import io.anuke.arc.collection.LongQueue; import io.anuke.arc.util.serialization.Json; import io.anuke.arc.util.serialization.JsonValue; import io.anuke.mindustry.Vars; -import io.anuke.mindustry.game.Rules; -import io.anuke.mindustry.game.SpawnGroup; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.game.Teams.TeamData; import io.anuke.mindustry.type.*; @SuppressWarnings("unchecked") @@ -36,6 +38,25 @@ public class JsonIO{ return Vars.content.getByName(ContentType.item, jsonData.asString()); } }); + + setSerializer(TeamData.class, new Serializer(){ + @Override + public void write(Json json, TeamData object, Class knownType){ + json.writeObjectStart(); + json.writeValue("brokenBlocks", object.brokenBlocks.toArray()); + json.writeValue("team", object.team.ordinal()); + json.writeObjectEnd(); + } + + @Override + public TeamData read(Json json, JsonValue jsonData, Class type){ + long[] blocks = jsonData.get("brokenBlocks").asLongArray(); + Team team = Team.all[jsonData.getInt("team", 0)]; + TeamData out = new TeamData(team, EnumSet.of(new Team[]{})); + out.brokenBlocks = new LongQueue(blocks); + return out; + } + }); }}; public static String write(Object object){ diff --git a/core/src/io/anuke/mindustry/io/SaveVersion.java b/core/src/io/anuke/mindustry/io/SaveVersion.java index fee4bf058d..839bed89fe 100644 --- a/core/src/io/anuke/mindustry/io/SaveVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveVersion.java @@ -1,13 +1,14 @@ package io.anuke.mindustry.io; -import io.anuke.arc.collection.Array; -import io.anuke.arc.collection.StringMap; +import io.anuke.arc.collection.*; import io.anuke.arc.util.Time; import io.anuke.arc.util.io.CounterInputStream; import io.anuke.mindustry.entities.Entities; import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.game.Teams.TeamData; +import io.anuke.mindustry.gen.BrokenBlock; import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.world.*; @@ -64,6 +65,7 @@ public abstract class SaveVersion extends SaveFileReader{ "wavetime", state.wavetime, "stats", JsonIO.write(state.stats), "rules", JsonIO.write(state.rules), + "teamdata", JsonIO.write(state.teams.getActive().toArray(TeamData.class)), "width", world.width(), "height", world.height() ).merge(tags)); @@ -77,6 +79,13 @@ public abstract class SaveVersion extends SaveFileReader{ state.stats = JsonIO.read(Stats.class, map.get("stats", "{}")); state.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); + + //only broken blocks are transferred over right now; nothing else + TeamData[] teams = JsonIO.read(TeamData[].class, map.get("teamdata", "[]")); + for(TeamData data : teams){ + state.teams.get(data.team).brokenBlocks = data.brokenBlocks; + } + Map worldmap = world.maps.byName(map.get("mapname", "\\\\\\")); world.setMap(worldmap == null ? new Map(StringMap.of( "name", map.get("mapname", "Unknown"), @@ -92,13 +101,13 @@ public abstract class SaveVersion extends SaveFileReader{ //floor + overlay for(int i = 0; i < world.width() * world.height(); i++){ - Tile tile = world.tile(i % world.width(), i / world.width()); + Tile tile = world.rawTile(i % world.width(), i / world.width()); stream.writeShort(tile.floorID()); stream.writeShort(tile.overlayID()); int consecutives = 0; for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ - Tile nextTile = world.tile(j % world.width(), j / world.width()); + Tile nextTile = world.rawTile(j % world.width(), j / world.width()); if(nextTile.floorID() != tile.floorID() || nextTile.overlayID() != tile.overlayID()){ break; @@ -113,7 +122,7 @@ public abstract class SaveVersion extends SaveFileReader{ //blocks for(int i = 0; i < world.width() * world.height(); i++){ - Tile tile = world.tile(i % world.width(), i / world.width()); + Tile tile = world.rawTile(i % world.width(), i / world.width()); stream.writeShort(tile.blockID()); if(tile.entity != null){ @@ -126,7 +135,7 @@ public abstract class SaveVersion extends SaveFileReader{ int consecutives = 0; for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ - Tile nextTile = world.tile(j % world.width(), j / world.width()); + Tile nextTile = world.rawTile(j % world.width(), j / world.width()); if(nextTile.blockID() != tile.blockID()){ break; @@ -264,6 +273,8 @@ public abstract class SaveVersion extends SaveFileReader{ } content.setTemporaryMapper(map); + + remapContent(); } public void writeContentHeader(DataOutput stream) throws IOException{ @@ -287,4 +298,17 @@ public abstract class SaveVersion extends SaveFileReader{ } } } + + /** sometimes it's necessary to remap IDs after the content header is read.*/ + public void remapContent(){ + for(Team team : Team.all){ + if(state.teams.isActive(team)){ + LongQueue queue = state.teams.get(team).brokenBlocks; + for(int i = 0; i < queue.size; i++){ + //remap broken block IDs + queue.set(i, BrokenBlock.block(queue.get(i), content.block(BrokenBlock.block(queue.get(i))).id)); + } + } + } + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java index 9d7cb84325..588d1410f2 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java @@ -69,6 +69,7 @@ public class CustomRulesDialog extends FloatingDialog{ title("$rules.title.enemy"); check("$rules.attack", b -> rules.attackMode = b, () -> rules.attackMode); + check("$rules.enemyCheat", b -> rules.enemyCheat = b, () -> rules.enemyCheat); number("$rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200)); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index ac19e1a480..c47f7524ce 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -123,7 +123,6 @@ public class SettingsMenuDialog extends SettingsDialog{ sound.add("[LIGHT_GRAY]there is no sound implemented in v4 yet"); game.screenshakePref(); - game.checkPref("effects", true); if(mobile){ game.checkPref("autotarget", true); } @@ -212,6 +211,7 @@ public class SettingsMenuDialog extends SettingsDialog{ } } + graphics.checkPref("effects", true); graphics.checkPref("playerchat", true); graphics.checkPref("minimap", !mobile); graphics.checkPref("fps", false);