diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index d816e2f14e..58836d6bf8 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -216,6 +216,7 @@ quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial c loading = [accent]Loading... reloading = [accent]Reloading Mods... saving = [accent]Saving... +cancelbuilding = [accent][[{0}][] to clear buildings wave = [accent]Wave {0} wave.waiting = [lightgray]Wave in {0} wave.waveInProgress = [lightgray]Wave in progress @@ -614,6 +615,7 @@ command.rally = Rally command.retreat = Retreat keybind.gridMode.name = Block Select keybind.gridModeShift.name = Category Select +keybind.clear_building.name = Clear Building keybind.press = Press a key... keybind.press.axis = Press an axis or key... keybind.screenshot.name = Map Screenshot diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 92e7c96134..0690c13505 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -177,7 +177,7 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(UnitDestroyEvent.class, e -> { - if(e.unit instanceof BaseUnit){ + if(e.unit instanceof BaseUnit && world.isZone()){ data.unlockContent(((BaseUnit)e.unit).getType()); } }); diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index 79069ca5b4..de24a552ec 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -6,8 +6,8 @@ import io.anuke.arc.collection.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; -import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.type.*; @@ -188,6 +188,11 @@ public interface BuilderTrait extends Entity, TeamTrait{ /** Add another build requests to the tail of the queue, if it doesn't exist there yet. */ default void addBuildRequest(BuildRequest place){ + addBuildRequest(place, true); + } + + /** Add another build requests to the queue, if it doesn't exist there yet. */ + default void addBuildRequest(BuildRequest place, boolean tail){ for(BuildRequest request : buildQueue()){ if(request.x == place.x && request.y == place.y){ return; @@ -197,7 +202,11 @@ public interface BuilderTrait extends Entity, TeamTrait{ if(tile != null && tile.entity instanceof BuildEntity){ place.progress = tile.entity().progress; } - buildQueue().addLast(place); + if(tail){ + buildQueue().addLast(place); + }else{ + buildQueue().addFirst(place); + } } /** @@ -258,15 +267,19 @@ public interface BuilderTrait extends Entity, TeamTrait{ /** Class for storing build requests. Can be either a place or remove request. */ class BuildRequest{ - public final int x, y, rotation; - public final Block block; - public final boolean breaking; + public int x, y, rotation; + public @Nullable Block block; + public boolean breaking; public boolean hasConfig; public int config; public float progress; public boolean initialized; + //animation variables + public float animScale; + public float animInvalid; + /** This creates a build request. */ public BuildRequest(int x, int y, int rotation, Block block){ this.x = x; @@ -285,13 +298,34 @@ public interface BuilderTrait extends Entity, TeamTrait{ this.breaking = true; } + public BuildRequest(){ + + } + + public BuildRequest set(int x, int y, int rotation, Block block){ + this.x = x; + this.y = y; + this.rotation = rotation; + this.block = block; + this.breaking = false; + return this; + } + + public float drawx(){ + return x*tilesize + block.offset(); + } + + public float drawy(){ + return y*tilesize + block.offset(); + } + public BuildRequest configure(int config){ this.config = config; this.hasConfig = true; return this; } - public Tile tile(){ + public @Nullable Tile tile(){ return world.tile(x, y); } diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 5b122c9ff2..a81d460394 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -21,7 +21,6 @@ import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.input.*; -import io.anuke.mindustry.input.InputHandler.*; import io.anuke.mindustry.io.*; import io.anuke.mindustry.net.Administration.*; import io.anuke.mindustry.net.*; @@ -424,7 +423,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; + if(!isLocal) return; + for(BuildRequest request : buildQueue()){ if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue; @@ -446,35 +446,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ request.x * tilesize + block.offset(), request.y * tilesize + block.offset(), rad); }else{ - Draw.color(); - PlaceDraw draw = PlaceDraw.instance; - - draw.scalex = 1; - draw.scaley = 1; - draw.rotation = request.rotation; - - if(last == null){ - request.block.getPlaceDraw(draw, request.rotation, request.x, request.y, request.rotation); - }else{ - request.block.getPlaceDraw(draw, request.rotation, last.x - request.x, last.y - request.y, last.rotation); - } - - TextureRegion region = draw.region; - - Draw.rect(region, - request.x * tilesize + request.block.offset(), request.y * tilesize + request.block.offset(), - region.getWidth() * 1f * Draw.scl * draw.scalex, - region.getHeight() * 1f * Draw.scl * draw.scaley, request.block.rotate ? draw.rotation * 90 : 0); - - Draw.color(Pal.accent); - for(int i = 0; i < 4; i++){ - Point2 p = Geometry.d8edge[i]; - float offset = -Math.max(request.block.size - 1, 0) / 2f * tilesize; - Draw.rect("block-select", request.x * tilesize + request.block.offset() + offset * p.x, request.y * tilesize + request.block.offset() + offset * p.y, i * 90); - } - Draw.color(); - - last = request; + request.block.drawRequest(request, control.input.allRequests(), true); } } diff --git a/core/src/io/anuke/mindustry/input/Binding.java b/core/src/io/anuke/mindustry/input/Binding.java index 8f599a872f..090c526a89 100644 --- a/core/src/io/anuke/mindustry/input/Binding.java +++ b/core/src/io/anuke/mindustry/input/Binding.java @@ -12,6 +12,7 @@ public enum Binding implements KeyBind{ select(KeyCode.MOUSE_LEFT), deselect(KeyCode.MOUSE_RIGHT), break_block(KeyCode.MOUSE_RIGHT), + clear_building(KeyCode.Q), rotate(new Axis(KeyCode.SCROLL)), rotateplaced(KeyCode.R), diagonal_placement(KeyCode.CONTROL_LEFT), diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 3bd752086e..90fccc3f4b 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -5,15 +5,16 @@ import io.anuke.arc.Graphics.*; import io.anuke.arc.Graphics.Cursor.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; -import io.anuke.arc.math.geom.*; +import io.anuke.arc.scene.*; import io.anuke.arc.scene.ui.*; -import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.input.PlaceUtils.*; +import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.*; import static io.anuke.arc.Core.scene; @@ -23,50 +24,28 @@ import static io.anuke.mindustry.input.PlaceMode.*; public class DesktopInput extends InputHandler{ /** Current cursor type. */ private Cursor cursorType = SystemCursor.arrow; - /** Position where the player started dragging a line. */ private int selectX, selectY; + /** Last known line positions.*/ + private int lastLineX, lastLineY; /** Whether selecting mode is active. */ private PlaceMode mode; /** Animation scale for line. */ private float selectScale; - private int prevX, prevY, prevRotation; - - /** Draws a placement icon for a specific block. */ - void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){ - if(validPlace(x, y, block, rotation)){ - block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation); - - Draw.color(); - Draw.mixcol(Pal.accent, 0.12f + Mathf.absin(Time.time(), 8f, 0.35f)); - Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(), - placeDraw.region.getWidth() * selectScale * Draw.scl * placeDraw.scalex, - placeDraw.region.getHeight() * selectScale * Draw.scl * placeDraw.scaley, - block.rotate ? placeDraw.rotation * 90 : 0); - - Draw.color(Pal.accent); - for(int i = 0; i < 4; i++){ - Point2 p = Geometry.d8edge[i]; - float offset = -Math.max(block.size - 1, 0) / 2f * tilesize; - if(i % 2 == 0) - Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90); - } - Draw.color(); - Draw.mixcol(); - }else{ - Draw.color(Pal.removeBack); - Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1); - Draw.color(Pal.remove); - Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1); - } - } - @Override public boolean isDrawing(){ return mode != none || block != null; } + @Override + public void buildUI(Group group){ + group.fill(t -> { + t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.isBuilding() ? 1f : 0f, 0.1f)); + t.table(Styles.black6, b -> b.add(Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.name())).style(Styles.outlineLabel)).margin(10f); + }); + } + @Override public void drawOutlined(){ Lines.stroke(1f); @@ -75,21 +54,13 @@ public class DesktopInput extends InputHandler{ //draw selection(s) if(mode == placing && block != null){ - prevX = selectX; - prevY = selectY; - prevRotation = rotation; - - iterateLine(selectX, selectY, cursorX, cursorY, l -> { - if(l.last && block.rotate){ - drawArrow(block, l.x, l.y, l.rotation); + for(int i = 0; i < lineRequests.size; i++){ + BuildRequest req = lineRequests.get(i); + if(i == lineRequests.size - 1){ + drawArrow(block, req.x, req.y, req.rotation); } - drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation); - - prevX = l.x; - prevY = l.y; - prevRotation = l.rotation; - }); - + drawRequest(lineRequests.get(i)); + } }else if(mode == breaking){ NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, selectX, selectY, cursorX, cursorY, false, maxLength, 1f); NormalizeResult dresult = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength); @@ -114,7 +85,7 @@ public class DesktopInput extends InputHandler{ if(block.rotate){ drawArrow(block, cursorX, cursorY, rotation); } - drawPlace(cursorX, cursorY, block, rotation, cursorX, cursorY, rotation); + drawRequest(cursorX, cursorY, block, rotation); block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation)); } @@ -211,11 +182,28 @@ public class DesktopInput extends InputHandler{ player.setMineTile(null); } + if(Core.input.keyTap(Binding.clear_building)){ + player.clearBuilding(); + } + + if(block == null || mode != placing){ + lineRequests.clear(); + } + + if((cursorX != lastLineX || cursorY != lastLineY) && isPlacing() && mode == placing){ + updateLine(selectX, selectY); + lastLineX = cursorX; + lastLineY = cursorY; + } + if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ if(isPlacing()){ selectX = cursorX; selectY = cursorY; + lastLineX = cursorX; + lastLineY = cursorY; mode = placing; + updateLine(selectX, selectY); }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.buildQueue().size == 0 && !droppingItem && @@ -227,10 +215,6 @@ public class DesktopInput extends InputHandler{ } }else if(Core.input.keyTap(Binding.deselect) && (block != null || mode != none || player.isBuilding()) && !(player.buildRequest() != null && player.buildRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){ - if(block == null){ - player.clearBuilding(); - } - block = null; mode = none; }else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){ @@ -240,7 +224,7 @@ public class DesktopInput extends InputHandler{ selectY = tileY(Core.input.mouseY()); } - if (mode == placing && block != null){ + if(mode == placing && block != null){ 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; @@ -252,10 +236,8 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){ if(mode == placing && block != null){ //touch up while placing, place everything in selection - iterateLine(selectX, selectY, cursorX, cursorY, l -> { - rotation = l.rotation; - tryPlaceBlock(l.x, l.y); - }); + flushRequests(lineRequests); + lineRequests.clear(); Events.fire(new LineConfirmEvent()); }else if(mode == breaking){ //touch up while breaking, break everything in selection NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength); diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 4caaf25677..3aae0c49ee 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -7,8 +7,11 @@ import io.anuke.arc.function.*; import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.*; +import io.anuke.arc.input.GestureDetector.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; +import io.anuke.arc.scene.*; +import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; @@ -26,7 +29,7 @@ import io.anuke.mindustry.world.*; import static io.anuke.mindustry.Vars.*; -public abstract class InputHandler implements InputProcessor{ +public abstract class InputHandler implements InputProcessor, GestureListener{ /** Used for dropping items. */ final static float playerSelectRange = mobile ? 17f : 11f; /** Maximum line length. */ @@ -41,9 +44,13 @@ public abstract class InputHandler implements InputProcessor{ public boolean overrideLineRotation; public int rotation; public boolean droppingItem; + public Group uiGroup; - protected PlaceDraw placeDraw = new PlaceDraw(); - private PlaceLine line = new PlaceLine(); + protected GestureDetector detector; + protected PlaceLine line = new PlaceLine(); + protected BuildRequest brequest = new BuildRequest(); + protected Array lineRequests = new Array<>(); + protected Array selectRequests = new Array<>(); //methods to override @@ -134,6 +141,14 @@ public abstract class InputHandler implements InputProcessor{ tile.block().configured(tile, player, value); } + public Eachable allRequests(){ + return cons -> { + for(BuildRequest request : player.buildQueue()) cons.accept(request); + for(BuildRequest request : selectRequests) cons.accept(request); + for(BuildRequest request : lineRequests) cons.accept(request); + }; + } + public OverlayFragment getFrag(){ return frag; } @@ -150,7 +165,11 @@ public abstract class InputHandler implements InputProcessor{ return Core.input.mouseY(); } - public void buildUI(Table table){ + public void buildPlacementUI(Table table){ + + } + + public void buildUI(Group group){ } @@ -170,6 +189,32 @@ public abstract class InputHandler implements InputProcessor{ return false; } + protected void flushRequests(Array requests){ + for(BuildRequest req : requests){ + if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ + player.addBuildRequest(req); + } + } + } + + protected void drawRequest(BuildRequest request){ + drawRequest(request.x, request.y, request.block, request.rotation); + } + + /** Draws a placement icon for a specific block. */ + protected void drawRequest(int x, int y, Block block, int rotation){ + brequest.set(x, y, rotation, block); + block.drawRequest(brequest, allRequests(), validPlace(x, y, block, rotation)); + } + + protected void updateLine(int selectX, int selectY){ + lineRequests.clear(); + iterateLine(selectX, selectY, tileX(getMouseX()), tileY(getMouseY()), l -> { + rotation = l.rotation; + lineRequests.add(new BuildRequest(l.x, l.y, l.rotation, block)); + }); + } + /** Handles tile tap events that are not platform specific. */ boolean tileTapped(Tile tile){ tile = tile.link(); @@ -216,7 +261,7 @@ public abstract class InputHandler implements InputProcessor{ //clear when the player taps on something else if(!consumed && !mobile && player.isBuilding() && block == null){ - player.clearBuilding(); + //player.clearBuilding(); block = null; return true; } @@ -301,16 +346,30 @@ public abstract class InputHandler implements InputProcessor{ table.clear(); } } + if(detector != null){ + Core.input.removeProcessor(detector); + } + if(uiGroup != null){ + uiGroup.remove(); + uiGroup = null; + } } public void add(){ + Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); Core.input.addProcessor(this); if(Core.scene != null){ Table table = (Table)Core.scene.find("inputTable"); if(table != null){ table.clear(); - buildUI(table); + buildPlacementUI(table); } + + uiGroup = new WidgetGroup(); + uiGroup.touchable(Touchable.childrenOnly); + uiGroup.setFillParent(true); + ui.hudGroup.addChild(uiGroup); + buildUI(uiGroup); } } @@ -356,6 +415,15 @@ public abstract class InputHandler implements InputProcessor{ } public boolean validPlace(int x, int y, Block type, int rotation){ + return validPlace(x, y, type, rotation, null); + } + + public boolean validPlace(int x, int y, Block type, int rotation, BuildRequest ignore){ + for(BuildRequest req : player.buildQueue()){ + if(req != ignore && !req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2))){ + return false; + } + } return Build.validPlace(player.getTeam(), x, y, type, rotation); } @@ -435,13 +503,6 @@ public abstract class InputHandler implements InputProcessor{ } } - public static class PlaceDraw{ - public int rotation, scalex, scaley; - public TextureRegion region; - - public static final PlaceDraw instance = new PlaceDraw(); - } - class PlaceLine{ public int x, y, rotation; public boolean last; diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index a5e8ec603f..5e634e51b7 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -2,12 +2,12 @@ package io.anuke.mindustry.input; import io.anuke.arc.*; import io.anuke.arc.collection.*; -import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.*; import io.anuke.arc.input.GestureDetector.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; +import io.anuke.arc.scene.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; @@ -36,7 +36,6 @@ public class MobileInput extends InputHandler implements GestureListener{ //gesture data private Vector2 vector = new Vector2(); private float lastZoom = -1; - private GestureDetector detector; /** Position where the player started dragging a line. */ private int lineStartX, lineStartY; @@ -50,9 +49,9 @@ public class MobileInput extends InputHandler implements GestureListener{ private float shiftDeltaX, shiftDeltaY; /** List of currently selected tiles to place. */ - private Array selection = new Array<>(); + private Array selection = new Array<>(); /** Place requests to be removed. */ - private Array removals = new Array<>(); + private Array removals = new Array<>(); /** Whether or not the player is currently shifting all placed tiles. */ private boolean selecting; /** Whether the player is currently in line-place mode. */ @@ -62,9 +61,9 @@ public class MobileInput extends InputHandler implements GestureListener{ /** Whether no recipe was available when switching to break mode. */ private Block lastBlock; /** Last placed request. Used for drawing block overlay. */ - private PlaceRequest lastPlaced; - - private int prevX, prevY, prevRotation; + private BuildRequest lastPlaced; + /** Down tracking for panning.*/ + private boolean down = false; //region utility methods @@ -99,10 +98,10 @@ public class MobileInput extends InputHandler implements GestureListener{ r2.setSize(block.size * tilesize); r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset()); - for(PlaceRequest req : selection){ + for(BuildRequest req : selection){ Tile other = req.tile(); - if(other == null || req.remove) continue; + if(other == null || req.breaking) continue; r1.setSize(req.block.size * tilesize); r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset()); @@ -128,16 +127,16 @@ public class MobileInput extends InputHandler implements GestureListener{ } /** Returns the selection request that overlaps this tile, or null. */ - PlaceRequest getRequest(Tile tile){ + BuildRequest getRequest(Tile tile){ r2.setSize(tilesize); r2.setCenter(tile.worldx(), tile.worldy()); - for(PlaceRequest req : selection){ + for(BuildRequest req : selection){ Tile other = req.tile(); if(other == null) continue; - if(!req.remove){ + if(!req.breaking){ r1.setSize(req.block.size * tilesize); r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset()); @@ -156,7 +155,7 @@ public class MobileInput extends InputHandler implements GestureListener{ return null; } - void removeRequest(PlaceRequest request){ + void removeRequest(BuildRequest request){ selection.removeValue(request, true); removals.add(request); } @@ -172,80 +171,8 @@ public class MobileInput extends InputHandler implements GestureListener{ //endregion //region UI and drawing - void drawRequest(PlaceRequest request, PlaceRequest prev){ - Tile tile = request.tile(); - - if(!request.remove){ - if(prev != null){ - request.block.getPlaceDraw(placeDraw, request.rotation, prev.x - request.x, prev.y - request.y, prev.rotation); - }else{ - request.block.getPlaceDraw(placeDraw, request.rotation, 0, 0, request.rotation); - } - - //draw placing request - float offset = request.block.offset(); - TextureRegion region = placeDraw.region; - - Draw.mixcol(Pal.accent, Mathf.clamp((1f - request.scale) / 0.5f + 0.12f + Mathf.absin(Time.time(), 8f, 0.35f))); - Draw.tint(Color.white, Pal.breakInvalid, request.redness); - - Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset, - region.getWidth() * request.scale * Draw.scl * placeDraw.scalex, - region.getHeight() * request.scale * Draw.scl * placeDraw.scaley, - request.block.rotate ? placeDraw.rotation * 90 : 0); - - Draw.mixcol(Pal.accent, 1f); - for(int i = 0; i < 4; i++){ - Point2 p = Geometry.d8edge[i]; - float poffset = -Math.max(request.block.size - 1, 0) / 2f * tilesize; - TextureRegion find = Core.atlas.find("block-select"); - if(i % 2 == 0) - Draw.rect("block-select", request.tile().x * tilesize + request.block.offset() + poffset * p.x, request.tile().y * tilesize + request.block.offset() + poffset * p.y, - find.getWidth() * Draw.scl * request.scale, find.getHeight() * Draw.scl * request.scale, i * 90); - } - Draw.color(); - }else{ - float rad = Math.max((tile.block().size * tilesize / 2f - 1) * request.scale, 1f); - - if(rad <= 1.01f) return; - Draw.mixcol(); - //draw removing request - Draw.tint(Pal.removeBack); - Lines.square(tile.drawx(), tile.drawy() - 1, rad); - Draw.tint(Pal.remove); - Lines.square(tile.drawx(), tile.drawy(), rad); - } - } - - /** Draws a placement icon for a specific block. */ - void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){ - if(validPlace(x, y, block, rotation) && !checkOverlapPlacement(x, y, block)){ - block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation); - - Draw.color(); - Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(), - placeDraw.region.getWidth() * Draw.scl * placeDraw.scalex, - placeDraw.region.getHeight() * Draw.scl * placeDraw.scaley, - block.rotate ? placeDraw.rotation * 90 : 0); - - Draw.color(Pal.accent); - for(int i = 0; i < 4; i++){ - Point2 p = Geometry.d8edge[i]; - float offset = -Math.max(block.size - 1, 0) / 2f * tilesize; - if(i % 2 == 0) - Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90); - } - Draw.color(); - }else{ - Draw.color(Pal.removeBack); - Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1); - Draw.color(Pal.remove); - Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1); - } - } - @Override - public void buildUI(Table table){ + public void buildPlacementUI(Table table){ table.addImage().color(Pal.gray).height(4f).colspan(4).growX(); table.row(); table.left().margin(0f).defaults().size(48f); @@ -267,12 +194,12 @@ public class MobileInput extends InputHandler implements GestureListener{ //confirm button table.addImageButton(Icon.checkSmall, Styles.clearPartiali, () -> { - for(PlaceRequest request : selection){ + for(BuildRequest request : selection){ Tile tile = request.tile(); //actually place/break all selected blocks if(tile != null){ - if(!request.remove){ + if(!request.breaking){ rotation = request.rotation; Block before = block; block = request.block; @@ -289,15 +216,17 @@ public class MobileInput extends InputHandler implements GestureListener{ selection.clear(); selecting = false; }).visible(() -> !selection.isEmpty()).name("confirmplace"); + } - Core.scene.table(t -> { - t.setName("cancelMobile"); - t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu)); - t.addImageTextButton("$cancel", Icon.cancelSmall, () -> { - player.clearBuilding(); - mode = none; - block = null; - }).width(155f); + @Override + public void buildUI(Group group){ + group.fill(t -> { + t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu)); + t.addImageTextButton("$cancel", Icon.cancelSmall, () -> { + player.clearBuilding(); + mode = none; + block = null; + }).width(155f); }); } @@ -316,46 +245,46 @@ public class MobileInput extends InputHandler implements GestureListener{ Lines.stroke(1f); //draw removals - for(PlaceRequest request : removals){ + for(BuildRequest request : removals){ Tile tile = request.tile(); if(tile == null) continue; - request.scale = Mathf.lerpDelta(request.scale, 0f, 0.2f); - request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f); + request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f); + request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f); - drawRequest(request, null); + drawRequest(request); } - PlaceRequest last = null; + BuildRequest last = null; //draw list of requests - for(PlaceRequest request : selection){ + for(BuildRequest request : selection){ Tile tile = request.tile(); if(tile == null) continue; - if((!request.remove && validPlace(tile.x, tile.y, request.block, request.rotation)) - || (request.remove && validBreak(tile.x, tile.y))){ - request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f); - request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f); + if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation)) + || (request.breaking && validBreak(tile.x, tile.y))){ + request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f); + request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f); }else{ - request.scale = Mathf.lerpDelta(request.scale, 0.6f, 0.1f); - request.redness = Mathf.lerpDelta(request.redness, 0.9f, 0.2f); + request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f); + request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0.9f, 0.2f); } Tmp.c1.set(Draw.getMixColor()); - if(!request.remove && request == lastPlaced && request.block != null){ + if(!request.breaking && request == lastPlaced && request.block != null){ Draw.mixcol(); if(request.block.rotate) drawArrow(request.block, tile.x, tile.y, request.rotation); } Draw.mixcol(Tmp.c1, 1f); - drawRequest(request, last); + drawRequest(request); //draw last placed request - if(!request.remove && request == lastPlaced && request.block != null){ + if(!request.breaking && request == lastPlaced && request.block != null){ Draw.mixcol(); request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation)); } @@ -374,20 +303,13 @@ public class MobileInput extends InputHandler implements GestureListener{ if(mode == placing && block != null){ //draw placing - prevX = lineStartX; - prevY = lineStartY; - prevRotation = rotation; - iterateLine(lineStartX, lineStartY, tileX, tileY, l -> { if(l.last && block.rotate){ drawArrow(block, l.x, l.y, l.rotation); } - drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation); + drawRequest(l.x, l.y, block, l.rotation); rotation = l.rotation; - prevX = l.x; - prevY = l.y; - prevRotation = l.rotation; }); }else if(mode == breaking){ //draw breaking @@ -441,28 +363,12 @@ public class MobileInput extends InputHandler implements GestureListener{ //endregion //region input events - @Override - public void add(){ - Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); - super.add(); - } - - @Override - public void remove(){ - super.remove(); - if(detector != null){ - Core.input.removeProcessor(detector); - } - - if(Core.scene != null && Core.scene.find("cancelMobile") != null){ - Core.scene.find("cancelMobile").remove(); - } - } - @Override public boolean touchDown(int screenX, int screenY, int pointer, KeyCode button){ if(state.is(State.menu) || player.isDead()) return false; + down = true; + //get tile on cursor Tile cursor = tileAt(screenX, screenY); @@ -489,6 +395,10 @@ public class MobileInput extends InputHandler implements GestureListener{ public boolean touchUp(int screenX, int screenY, int pointer, KeyCode button){ lastZoom = renderer.getScale(); + if(!Core.input.isTouched()){ + down = false; + } + //place down a line if in line mode if(lineMode){ int tileX = tileX(screenX); @@ -501,8 +411,8 @@ public class MobileInput extends InputHandler implements GestureListener{ return; } - PlaceRequest request = new PlaceRequest(l.x, l.y, block, l.rotation); - request.scale = 1f; + BuildRequest request = new BuildRequest(l.x, l.y, l.rotation, block); + request.animScale = 1f; selection.add(request); }); Events.fire(new LineConfirmEvent()); @@ -521,8 +431,8 @@ public class MobileInput extends InputHandler implements GestureListener{ if(tar == null) continue; if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){ - PlaceRequest request = new PlaceRequest(tar.x, tar.y); - request.scale = 1f; + BuildRequest request = new BuildRequest(tar.x, tar.y); + request.animScale = 1f; selection.add(request); } } @@ -584,11 +494,11 @@ public class MobileInput extends InputHandler implements GestureListener{ removeRequest(getRequest(cursor)); }else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){ //add to selection queue if it's a valid place position - selection.add(lastPlaced = new PlaceRequest(cursor.x, cursor.y, block, rotation)); + selection.add(lastPlaced = new BuildRequest(cursor.x, cursor.y, rotation, block)); }else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){ //add to selection queue if it's a valid BREAK position cursor = cursor.link(); - selection.add(new PlaceRequest(cursor.x, cursor.y)); + selection.add(new BuildRequest(cursor.x, cursor.y)); }else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){ tryBeginMine(cursor); } @@ -690,9 +600,9 @@ public class MobileInput extends InputHandler implements GestureListener{ //remove place requests that have disappeared for(int i = removals.size - 1; i >= 0; i--){ - PlaceRequest request = removals.get(i); + BuildRequest request = removals.get(i); - if(request.scale <= 0.0001f){ + if(request.animScale <= 0.0001f){ removals.remove(i); i--; } @@ -712,6 +622,8 @@ public class MobileInput extends InputHandler implements GestureListener{ return false; } + if(!down) return false; + if(selecting){ //pan all requests shiftDeltaX += deltaX; shiftDeltaY += deltaY; @@ -720,8 +632,8 @@ public class MobileInput extends InputHandler implements GestureListener{ int shiftedY = (int)(shiftDeltaY / tilesize); if(Math.abs(shiftedX) > 0 || Math.abs(shiftedY) > 0){ - for(PlaceRequest req : selection){ - if(req.remove) continue; //don't shift removal requests + for(BuildRequest req : selection){ + if(req.breaking) continue; //don't shift removal requests req.x += shiftedX; req.y += shiftedY; } @@ -756,33 +668,4 @@ public class MobileInput extends InputHandler implements GestureListener{ } //endregion - - private class PlaceRequest{ - int x, y; - Block block; - int rotation; - boolean remove; - - //animation variables - float scale; - float redness; - - PlaceRequest(int x, int y, Block block, int rotation){ - this.x = x; - this.y = y; - this.block = block; - this.rotation = rotation; - this.remove = false; - } - - PlaceRequest(int x, int y){ - this.x = x; - this.y = y; - this.remove = true; - } - - Tile tile(){ - return world.tile(x, y); - } - } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java index c21f08a4e2..308209f0df 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java @@ -263,7 +263,7 @@ public class PlacementFragment extends Fragment{ blocksSelect.margin(4).marginTop(0); blocksSelect.table(blocks -> blockTable = blocks).grow(); blocksSelect.row(); - blocksSelect.table(control.input::buildUI).name("inputTable").growX(); + blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX(); }).fillY().bottom().touchable(Touchable.enabled); frame.table(categories -> { categories.defaults().size(50f); diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 7f886a05e1..56ba00fef9 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -19,11 +19,11 @@ import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; +import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.input.InputHandler.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.blocks.*; @@ -667,10 +667,21 @@ public class Block extends BlockStorage{ } } - public void getPlaceDraw(PlaceDraw draw, int rotation, int prevX, int prevY, int prevRotation){ - draw.region = icon(Cicon.full); - draw.scalex = draw.scaley = 1; - draw.rotation = rotation; + public void drawRequest(BuildRequest req, Eachable list, boolean valid){ + Draw.mixcol(!valid ? Pal.breakInvalid : Pal.accent, 0.12f + Mathf.absin(Time.time(), 8f, 0.35f)); + drawRequestRegion(req, list); + + //Draw.color(Pal.accent); + for(int i = 0; i < 4; i++){ + Point2 p = Geometry.d8edge[i]; + float offset = -Math.max(size - 1, 0) / 2f * tilesize; + //if(i % 2 == 0) Draw.rect("block-select", req.drawx() + offset * p.x, req.drawy() + offset * p.y, i * 90); + } + Draw.reset(); + } + + public void drawRequestRegion(BuildRequest req, Eachable list){ + Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(), !rotate ? 0 : req.rotation * 90); } @Override @@ -785,6 +796,10 @@ public class Block extends BlockStorage{ return ((size + 1) % 2) * tilesize / 2f; } + public Rectangle bounds(int x, int y, Rectangle rect){ + return rect.setSize(size * tilesize).setCenter(x * tilesize + offset(), y * tilesize + offset()); + } + public boolean isMultiblock(){ return size > 1; } diff --git a/core/src/io/anuke/mindustry/world/Edges.java b/core/src/io/anuke/mindustry/world/Edges.java index dc9586aca0..623dd1d434 100644 --- a/core/src/io/anuke/mindustry/world/Edges.java +++ b/core/src/io/anuke/mindustry/world/Edges.java @@ -50,10 +50,14 @@ public class Edges{ } public static Tile getFacingEdge(Tile tile, Tile other){ - if(!tile.block().isMultiblock()) return tile; - int size = tile.block().size; - return world.tile(tile.x + Mathf.clamp(other.x - tile.x, -(size - 1) / 2, (size / 2)), - tile.y + Mathf.clamp(other.y - tile.y, -(size - 1) / 2, (size / 2))); + return getFacingEdge(tile.block, tile.x, tile.y, other); + } + + public static Tile getFacingEdge(Block block, int tilex, int tiley, Tile other){ + if(!block.isMultiblock()) return world.tile(tilex, tiley); + int size = block.size; + return world.tile(tilex + Mathf.clamp(other.x - tilex, -(size - 1) / 2, (size / 2)), + tiley + Mathf.clamp(other.y - tiley, -(size - 1) / 2, (size / 2))); } public static Vector2[] getPixelPolygon(float radius){ diff --git a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java index 22e649b9c3..37c3ccc6fa 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java @@ -110,8 +110,8 @@ public class BuildBlock extends Block{ //if the target is constructible, begin constructing if(entity.cblock != null){ - player.clearBuilding(); - player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock)); + //player.clearBuilding(); + player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock), false); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ArmoredConveyor.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ArmoredConveyor.java index 08ae878b5a..6a5064cfcb 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ArmoredConveyor.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ArmoredConveyor.java @@ -1,6 +1,6 @@ package io.anuke.mindustry.world.blocks.distribution; -import io.anuke.arc.math.*; +import io.anuke.arc.math.geom.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; @@ -16,11 +16,8 @@ public class ArmoredConveyor extends Conveyor{ } @Override - protected boolean blends(Tile tile, int direction){ - Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4)); - if(other != null) other = other.link(); - - return other != null && other.block().outputsItems() - && ((tile.getNearby(tile.rotation()) == other) || ((!other.block().rotate && Edges.getFacingEdge(other, tile).relativeTo(tile) == tile.rotation()) || (other.block().rotate && other.getNearby(other.rotation()) == tile))); + protected boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){ + return otherblock.outputsItems() && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery) + || ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == tile.rotation()) || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y))); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java index faf6645c6b..5b116f9875 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java @@ -2,20 +2,23 @@ package io.anuke.mindustry.world.blocks.distribution; import io.anuke.arc.*; import io.anuke.arc.collection.*; +import io.anuke.arc.function.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; import io.anuke.arc.util.*; +import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.input.InputHandler.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.meta.*; import java.io.*; +import java.util.*; import static io.anuke.mindustry.Vars.*; @@ -27,6 +30,8 @@ public class Conveyor extends Block{ private static ItemPos pos2 = new ItemPos(); private final Vector2 tr1 = new Vector2(); private final Vector2 tr2 = new Vector2(); + private final int[] blendresult = new int[3]; + private final BuildRequest[] directionals = new BuildRequest[4]; private TextureRegion[][] regions = new TextureRegion[7][4]; @@ -90,55 +95,84 @@ public class Conveyor extends Block{ super.onProximityUpdate(tile); ConveyorEntity entity = tile.entity(); - entity.blendbits = 0; - entity.blendsclx = entity.blendscly = 1; - - if(blends(tile, 2) && blends(tile, 1) && blends(tile, 3)){ - entity.blendbits = 3; - }else if(blends(tile, 1) && blends(tile, 3)){ - entity.blendbits = 4; - }else if(blends(tile, 1) && blends(tile, 2)){ - entity.blendbits = 2; - }else if(blends(tile, 3) && blends(tile, 2)){ - entity.blendbits = 2; - entity.blendscly = -1; - }else if(blends(tile, 1)){ - entity.blendbits = 1; - entity.blendscly = -1; - }else if(blends(tile, 3)){ - entity.blendbits = 1; - } + int[] bits = buildBlending(tile, tile.rotation(), null); + entity.blendbits = bits[0]; + entity.blendsclx = bits[1]; + entity.blendscly = bits[2]; } @Override - public void getPlaceDraw(PlaceDraw draw, int rotation, int prevX, int prevY, int prevRotation){ - draw.rotation = rotation; - draw.scalex = draw.scaley = 1; + public void drawRequestRegion(BuildRequest req, Eachable list){ + if(req.tile() == null) return; + Arrays.fill(directionals, null); + list.each(other -> { + if(other.breaking || other == req) return; + + int i = 0; + for(Point2 point : Geometry.d4){ + int x = req.x + point.x, y = req.y + point.y; + if(x >= other.x -(other.block.size - 1) / 2 && x <= other.x + (other.block.size / 2) && y >= other.y -(other.block.size - 1) / 2 && y <= other.y + (other.block.size / 2)){ + directionals[i] = other; + } + i++; + } + }); + + int[] bits = buildBlending(req.tile(), req.rotation, directionals); + + TextureRegion region = regions[bits[0]][0]; + + Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl, region.getHeight() * bits[2] * Draw.scl, req.rotation * 90); + } + + protected int[] buildBlending(Tile tile, int rotation, BuildRequest[] directional){ int blendbits = 0; + int blendsclx = 1, blendscly = 1; - if(blends(rotation, 1, prevX, prevY, prevRotation)){ + if(blends(tile, rotation, directional, 2) && blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 3)){ + blendbits = 3; + }else if(blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 3)){ + blendbits = 4; + }else if(blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 2)){ + blendbits = 2; + }else if(blends(tile, rotation, directional, 3) && blends(tile, rotation, directional, 2)){ + blendbits = 2; + blendscly = -1; + }else if(blends(tile, rotation, directional, 1)){ blendbits = 1; - draw.scaley = -1; - }else if(blends(rotation, 3, prevX, prevY, prevRotation)){ + blendscly = -1; + }else if(blends(tile, rotation, directional, 3)){ blendbits = 1; } - draw.rotation = rotation; - draw.region = regions[blendbits][0]; + blendresult[0] = blendbits; + blendresult[1] = blendsclx; + blendresult[2] = blendscly; + return blendresult; } - protected boolean blends(int rotation, int offset, int prevX, int prevY, int prevRotation){ - Point2 left = Geometry.d4(rotation - offset); - return left.equals(prevX, prevY) && prevRotation == Mathf.mod(rotation + offset, 4); + protected boolean blends(Tile tile, int rotation, @Nullable BuildRequest[] directional, int direction){ + int realDir = Mathf.mod(rotation - direction, 4); + if(directional != null && directional[realDir] != null){ + BuildRequest req = directional[realDir]; + //Log.info("Check if blends: {0},{1} {2} | {3},{4} {5}", tile.x, tile.y, rotation, req.x, req.y, req.rotation); + if(blends(tile, rotation, req.x, req.y, req.rotation, req.block)){ + return true; + } + } + return blends(tile, rotation, direction); } - protected boolean blends(Tile tile, int direction){ - Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4)); + protected boolean blends(Tile tile, int rotation, int direction){ + Tile other = tile.getNearby(Mathf.mod(rotation - direction, 4)); if(other != null) other = other.link(); + return other != null && blends(tile, rotation, other.x, other.y, other.rotation(), other.block()); + } - return other != null && other.block().outputsItems() - && ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile)); + protected boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){ + return otherblock.outputsItems() && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery) + || (!otherblock.rotate || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y))); } @Override diff --git a/tests/src/test/java/ZoneTests.java b/tests/src/test/java/ZoneTests.java index ce5dedc053..a35355b0a0 100644 --- a/tests/src/test/java/ZoneTests.java +++ b/tests/src/test/java/ZoneTests.java @@ -1,5 +1,6 @@ import io.anuke.arc.collection.*; import io.anuke.arc.util.*; +import io.anuke.mindustry.core.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.type.*; @@ -28,6 +29,7 @@ public class ZoneTests{ @TestFactory DynamicTest[] testZoneValidity(){ Array out = new Array<>(); + if(world == null) world = new World(); for(Zone zone : content.zones()){ out.add(dynamicTest(zone.name, () -> {