From df78412896302d8d4e4720a33b094f4d186fbfca Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 11 Jun 2019 23:31:57 -0400 Subject: [PATCH] Desktop/mobile descriptive tool modes --- .../sprites/blocks/turrets/salvo.png | Bin 5697 -> 5778 bytes core/assets/bundles/bundle.properties | 15 ++ core/assets/maps/groundZero.msav | Bin 8272 -> 8284 bytes core/assets/maps/saltFlats.msav | Bin 15554 -> 15650 bytes .../io/anuke/mindustry/editor/EditorTool.java | 221 ++++++++++-------- .../io/anuke/mindustry/editor/MapEditor.java | 108 ++++++++- .../mindustry/editor/MapEditorDialog.java | 95 +++++++- .../anuke/mindustry/editor/MapInfoDialog.java | 68 +++--- .../io/anuke/mindustry/editor/MapView.java | 31 +-- core/src/io/anuke/mindustry/net/Net.java | 19 +- core/src/io/anuke/mindustry/world/Block.java | 14 ++ core/src/io/anuke/mindustry/world/Tile.java | 12 +- 12 files changed, 407 insertions(+), 176 deletions(-) diff --git a/core/assets-raw/sprites/blocks/turrets/salvo.png b/core/assets-raw/sprites/blocks/turrets/salvo.png index f43f7bbd47aa57ce7a965e67c27eeda67a236f50..c15a9d47cd1a64b219df670a2adf5921993fb6dd 100644 GIT binary patch delta 5317 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 HB{Ts5p8)uV diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 74c88600fc..b106eca042 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -254,6 +254,20 @@ editor.mapname = Map Name: editor.overwrite = [accent]Warning!\nThis overwrites an existing map. editor.overwrite.confirm = [scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? editor.selectmap = Select a map to load: + +toolmode.replace = Replace +toolmode.replace.description = Draws only on solid blocks. +toolmode.replaceall = Replace All +toolmode.replaceall.description = Replace all blocks in map. +toolmode.straight = Straight +toolmode.straight.description = Draws only straight lines. +toolmode.square = Square +toolmode.square.description = Square brush. +toolmode.eraseores = Erase Ores +toolmode.eraseores.description = Erase only ores. +toolmode.fillteams = Fill Teams +toolmode.fillteams.description = Fill teams instead of blocks. + filters.empty = [LIGHT_GRAY]No filters! Add one with the button below. filter.distort = Distort filter.noise = Noise @@ -276,6 +290,7 @@ filter.option.floor2 = Secondary Floor filter.option.threshold2 = Secondary Threshold filter.option.radius = Radius filter.option.percentile = Percentile + width = Width: height = Height: menu = Menu diff --git a/core/assets/maps/groundZero.msav b/core/assets/maps/groundZero.msav index ee0593027f65bf67cbef72dcb6042e675918bcdc..cafa3e5e868d1e48a54d66a7ca2530aeff94fbb4 100644 GIT binary patch literal 8284 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 Gs|x@$aF{ay literal 8272 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 diff --git a/core/assets/maps/saltFlats.msav b/core/assets/maps/saltFlats.msav index 687a9f628bd99b050dd3013b6f3403cd2881d130..d3adf86160e468c654f132086c3331b9b48491b0 100644 GIT binary patch delta 15407 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 M`uU&1EAVwU0P2n}5C8xG delta 15383 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 BK->TT diff --git a/core/src/io/anuke/mindustry/editor/EditorTool.java b/core/src/io/anuke/mindustry/editor/EditorTool.java index 7eb6ffa334..b81661cb3d 100644 --- a/core/src/io/anuke/mindustry/editor/EditorTool.java +++ b/core/src/io/anuke/mindustry/editor/EditorTool.java @@ -1,13 +1,14 @@ package io.anuke.mindustry.editor; -import io.anuke.arc.Core; import io.anuke.arc.collection.IntArray; -import io.anuke.arc.function.IntPositionConsumer; -import io.anuke.arc.input.KeyCode; -import io.anuke.arc.util.*; +import io.anuke.arc.function.*; +import io.anuke.arc.math.Mathf; +import io.anuke.arc.math.geom.Bresenham2; +import io.anuke.arc.util.Structs; +import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.Blocks; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.world.*; -import io.anuke.mindustry.world.blocks.*; public enum EditorTool{ zoom, @@ -16,12 +17,34 @@ public enum EditorTool{ if(!Structs.inBounds(x, y, editor.width(), editor.height())) return; Tile tile = editor.tile(x, y).link(); - editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block(); } }, - line, - pencil{ + line("replace", "straight"){ + + @Override + public void touchedLine(MapEditor editor, int x1, int y1, int x2, int y2){ + //straight + if(mode == 1){ + if(Math.abs(x2 - x1) > Math.abs(y2 - y1)){ + y2 = y1; + }else{ + x2 = x1; + } + } + + Bresenham2.line(x1, y1, x2, y2, (x, y) -> { + if(mode == 0){ + //replace + editor.drawBlocksReplace(x, y); + }else{ + //normal + editor.drawBlocks(x, y); + } + }); + } + }, + pencil("replace", "square"){ { edit = true; draggable = true; @@ -29,10 +52,20 @@ public enum EditorTool{ @Override public void touched(MapEditor editor, int x, int y){ - editor.draw(x, y, isPaint()); + if(mode == -1){ + //normal mode + editor.drawBlocks(x, y); + }else if(mode == 0){ + //replace mode + editor.drawBlocksReplace(x, y); + }else if(mode == 1){ + //square mode + editor.drawBlocks(x, y, true, tile -> true); + } + } }, - eraser{ + eraser("eraseores"){ { edit = true; draggable = true; @@ -40,19 +73,25 @@ public enum EditorTool{ @Override public void touched(MapEditor editor, int x, int y){ - editor.draw(x, y, isPaint(), Blocks.air); + editor.drawCircle(x, y, tile -> { + if(mode == -1){ + //erase block + Vars.world.removeBlock(tile); + }else if(mode == 0){ + //erase ore + tile.clearOverlay(); + } + }); } }, - fill{ + fill("replaceall", "fillteams"){ { edit = true; } IntArray stack = new IntArray(); - Block dest; - boolean isFloor; - MapEditor data; + @Override public void touched(MapEditor editor, int x, int y){ if(!Structs.inBounds(x, y, editor.width(), editor.height())) return; Tile tile = editor.tile(x, y); @@ -63,74 +102,57 @@ public enum EditorTool{ return; } - data = editor; - isFloor = editor.drawBlock instanceof Floor; + //mode 0 or 1, fill everything with the floor/tile or replace it + if(mode == 0 || mode == -1){ + Predicate tester; + Consumer setter; - Block floor = tile.floor(); - Block block = tile.block(); - boolean synth = editor.drawBlock.synthetic(); - - Block draw = editor.drawBlock; - dest = draw instanceof OverlayFloor ? tile.overlay() : isFloor ? floor : block; - - if(dest == draw || block instanceof BlockPart || block.isMultiblock()){ - return; - } - - boolean alt = isAlt(); - - int width = editor.width(); - int height = editor.height(); - - IntPositionConsumer writer = (px, py) -> { - Tile write = editor.tile(px, py); - - if(isFloor){ - if(alt && !(draw instanceof OverlayFloor)){ - Block ore = write.overlay(); - write.setFloor((Floor)draw); - write.setOverlay(ore); - }else{ - write.setFloor((Floor)draw); - } + if(editor.drawBlock.isOverlay()){ + Block dest = tile.overlay(); + tester = t -> t.overlay() == dest; + setter = t -> t.setOverlay(editor.drawBlock); + }else if(editor.drawBlock.isFloor()){ + Block dest = tile.floor(); + tester = t -> t.floor() == dest; + setter = t -> t.setFloorUnder(editor.drawBlock.asFloor()); }else{ - write.setBlock(draw); + Block dest = tile.block(); + tester = t -> t.block() == dest; + setter = t -> t.setBlock(editor.drawBlock); } - if(synth){ - write.setTeam(editor.drawTeam); - } + //replace only when the mode is 0 using the specified functions + fill(editor, x, y, mode == 0, tester, setter); + }else if(mode == 1){ //mode 1 is team fill - if(draw.rotate){ - write.rotation((byte)editor.rotation); - } - }; + //only fill synthetic blocks, it's meaningless otherwise + if(tile.link().synthetic()){ - if(isAlt()){ - //fill all of the same type regardless of borders + Team dest = tile.getTeam(); + fill(editor, x, y, false, t -> t.getTeam() == dest, t -> t.setTeam(editor.drawTeam)); + } + } + } + + void fill(MapEditor editor, int x, int y, boolean replace, Predicate tester, Consumer filler){ + int width = editor.width(), height = editor.height(); + + if(replace){ + //just do it on everything for(int cx = 0; cx < width; cx++){ for(int cy = 0; cy < height; cy++){ - if(eq(cx, cy)){ - writer.accept(cx, cy); - } - } - } - }else if(isAlt2()){ - //fill all teams. - for(int cx = 0; cx < width; cx++){ - for(int cy = 0; cy < height; cy++){ - Tile write = editor.tile(cx, cy); - if(write.block().synthetic()){ - write.setTeam(editor.drawTeam); + Tile tile = editor.tile(cx, cy); + if(tester.test(tile)){ + filler.accept(tile); } } } + }else{ - //normal fill + //perform flood fill int x1; stack.clear(); - stack.add(Pos.get(x, y)); while(stack.size > 0){ @@ -139,23 +161,23 @@ public enum EditorTool{ y = Pos.y(popped); x1 = x; - while(x1 >= 0 && eq(x1, y)) x1--; + while(x1 >= 0 && tester.test(editor.tile(x1, y))) x1--; x1++; boolean spanAbove = false, spanBelow = false; - while(x1 < width && eq(x1, y)){ - writer.accept(x1, y); + while(x1 < width && tester.test(editor.tile(x1, y))){ + filler.accept(editor.tile(x1, y)); - if(!spanAbove && y > 0 && eq(x1, y - 1)){ + if(!spanAbove && y > 0 && tester.test(editor.tile(x1, y - 1))){ stack.add(Pos.get(x1, y - 1)); spanAbove = true; - }else if(spanAbove && !eq(x1, y - 1)){ + }else if(spanAbove && !tester.test(editor.tile(x1, y - 1))){ spanAbove = false; } - if(!spanBelow && y < height - 1 && eq(x1, y + 1)){ + if(!spanBelow && y < height - 1 && tester.test(editor.tile(x1, y + 1))){ stack.add(Pos.get(x1, y + 1)); spanBelow = true; - }else if(spanBelow && y < height - 1 && !eq(x1, y + 1)){ + }else if(spanBelow && y < height - 1 && !tester.test(editor.tile(x1, y + 1))){ spanBelow = false; } x1++; @@ -163,14 +185,10 @@ public enum EditorTool{ } } } - - boolean eq(int px, int py){ - Tile tile = data.tile(px, py); - - return (data.drawBlock instanceof OverlayFloor ? tile.overlay() : isFloor ? tile.floor() : tile.block()) == dest && !(data.drawBlock instanceof OverlayFloor && tile.floor().isLiquid); - } }, - spray{ + spray("replace"){ + final double chance = 0.012; + { edit = true; draggable = true; @@ -178,25 +196,40 @@ public enum EditorTool{ @Override public void touched(MapEditor editor, int x, int y){ - editor.draw(x, y, isPaint(), editor.drawBlock, 0.012); + + //floor spray + if(editor.drawBlock.isFloor()){ + editor.drawCircle(x, y, tile -> { + if(Mathf.chance(chance)){ + tile.setFloor(editor.drawBlock.asFloor()); + } + }); + }else if(mode == 0){ //replace-only mode, doesn't affect air + editor.drawBlocks(x, y, tile -> Mathf.chance(chance) && tile.block() != Blocks.air); + }else{ + editor.drawBlocks(x, y, tile -> Mathf.chance(chance)); + } } }; - boolean edit, draggable; + /** All the internal alternate placement modes of this tool. */ + public final String[] altModes; + /** The current alternate placement mode. -1 is the standard mode, no changes.*/ + public int mode = -1; + /** Whether this tool causes canvas changes when touched.*/ + public boolean edit; + /** Whether this tool should be dragged across the canvas when the mouse moves.*/ + public boolean draggable; - public static boolean isPaint(){ - return Core.input.keyDown(KeyCode.CONTROL_LEFT); + EditorTool(){ + this(new String[]{}); } - public static boolean isAlt(){ - return Core.input.keyDown(KeyCode.TAB); + EditorTool(String... altModes){ + this.altModes = altModes; } - public static boolean isAlt2(){ - return Core.input.keyDown(KeyCode.GRAVE); - } + public void touched(MapEditor editor, int x, int y){} - public void touched(MapEditor editor, int x, int y){ - - } + public void touchedLine(MapEditor editor, int x1, int y1, int x2, int y2){} } diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index 13824d0d8a..dd1cecd4d3 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -2,6 +2,8 @@ package io.anuke.mindustry.editor; import io.anuke.arc.collection.StringMap; import io.anuke.arc.files.FileHandle; +import io.anuke.arc.function.Consumer; +import io.anuke.arc.function.Predicate; import io.anuke.arc.graphics.Pixmap; import io.anuke.arc.math.Mathf; import io.anuke.arc.util.Structs; @@ -132,15 +134,111 @@ public class MapEditor{ return world.height(); } - public void draw(int x, int y, boolean paint){ - draw(x, y, paint, drawBlock); + public void drawBlocksReplace(int x, int y){ + drawBlocks(x, y, tile -> tile.block() != Blocks.air || drawBlock.isFloor()); } - public void draw(int x, int y, boolean paint, Block drawBlock){ - draw(x, y, paint, drawBlock, 1.0); + public void drawBlocks(int x, int y){ + drawBlocks(x, y, false, tile -> true); } - public void draw(int x, int y, boolean paint, Block drawBlock, double chance){ + public void drawBlocks(int x, int y, Predicate tester){ + drawBlocks(x, y, false, tester); + } + + public void drawBlocks(int x, int y, boolean square, Predicate tester){ + if(drawBlock.isMultiblock()){ + x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1); + y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1); + + int offsetx = -(drawBlock.size - 1) / 2; + int offsety = -(drawBlock.size - 1) / 2; + + for(int dx = 0; dx < drawBlock.size; dx++){ + for(int dy = 0; dy < drawBlock.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; + + if(Structs.inBounds(worldx, worldy, width(), height())){ + Tile tile = tile(worldx, worldy); + + Block block = tile.block(); + + //bail out if there's anything blocking the way + if(block.isMultiblock() || block instanceof BlockPart){ + return; + } + + renderer.updatePoint(worldx, worldy); + } + } + } + + world.setBlock(tile(x, y), drawBlock, drawTeam); + }else{ + + boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; + + Consumer drawer = tile -> { + if(!tester.test(tile)) return; + + //remove linked tiles blocking the way + if(!isFloor && (tile.isLinked() || tile.block().isMultiblock())){ + world.removeBlock(tile.link()); + } + + if(isFloor){ + tile.setFloor(drawBlock.asFloor()); + }else{ + tile.setBlock(drawBlock); + if(drawBlock.synthetic()){ + tile.setTeam(drawTeam); + } + if(drawBlock.rotate){ + tile.rotation((byte)rotation); + } + } + }; + + if(square){ + drawSquare(x, y, drawer); + }else{ + drawCircle(x, y, drawer); + } + } + } + + public void drawCircle(int x, int y, Consumer drawer){ + for(int rx = -brushSize; rx <= brushSize; rx++){ + for(int ry = -brushSize; ry <= brushSize; ry++){ + if(Mathf.dst2(rx, ry) <= (brushSize - 0.5f) * (brushSize - 0.5f)){ + int wx = x + rx, wy = y + ry; + + if(wx < 0 || wy < 0 || wx >= width() || wy >= height()){ + continue; + } + + drawer.accept(tile(wx, wy)); + } + } + } + } + + public void drawSquare(int x, int y, Consumer drawer){ + for(int rx = -brushSize; rx <= brushSize; rx++){ + for(int ry = -brushSize; ry <= brushSize; ry++){ + int wx = x + rx, wy = y + ry; + + if(wx < 0 || wy < 0 || wx >= width() || wy >= height()){ + continue; + } + + drawer.accept(tile(wx, wy)); + } + } + } + + public void draw_DEPRECATED(int x, int y, boolean paint, Block drawBlock, double chance){ boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air; Tile[][] tiles = world.getTiles(); diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 89c76b5126..ff7404bcca 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -12,8 +12,10 @@ import io.anuke.arc.input.KeyCode; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.scene.actions.Actions; +import io.anuke.arc.scene.event.Touchable; import io.anuke.arc.scene.style.TextureRegionDrawable; import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.TextButton.TextButtonStyle; import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.scene.ui.layout.Unit; import io.anuke.arc.util.*; @@ -21,6 +23,7 @@ import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.io.JsonIO; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; @@ -380,15 +383,77 @@ public class MapEditorDialog extends Dialog implements Disposable{ ButtonGroup group = new ButtonGroup<>(); Consumer addTool = tool -> { + Table[] lastTable = {null}; + ImageButton button = new ImageButton("icon-" + tool.name(), "clear-toggle"); - button.clicked(() -> view.setTool(tool)); + button.clicked(() -> { + view.setTool(tool); + if(lastTable[0] != null){ + lastTable[0].remove(); + } + }); button.resizeImage(16 * 2f); button.update(() -> button.setChecked(view.getTool() == tool)); group.add(button); - if(tool == EditorTool.pencil) - button.setChecked(true); - tools.add(button); + if(tool.altModes.length > 0){ + button.clicked(l -> { + if(!mobile){ + //desktop: rightclick + l.setButton(KeyCode.MOUSE_RIGHT); + } + }, e -> { + //need to double tap + if(mobile && e.getTapCount() < 2){ + return; + } + + if(lastTable[0] != null){ + lastTable[0].remove(); + } + + Table table = new Table("dialogDim"); + table.defaults().size(280f, 70f); + + for(int i = 0; i < tool.altModes.length; i++){ + int mode = i; + String name = tool.altModes[i]; + + table.addButton(b -> { + b.left(); + b.marginLeft(6); + b.setStyle(Core.scene.skin.get("clear-toggle", TextButtonStyle.class)); + b.add(Core.bundle.get("toolmode." + name)).left(); + b.row(); + b.add(Core.bundle.get("toolmode." + name + ".description")).color(Color.LIGHT_GRAY).left(); + }, () -> { + tool.mode = (tool.mode == mode ? -1 : mode); + table.remove(); + }).update(b -> b.setChecked(tool.mode == mode)); + table.row(); + } + + table.update(() -> { + Vector2 v = button.localToStageCoordinates(Tmp.v1.setZero()); + table.setPosition(v.x, v.y, Align.topLeft); + }); + + table.pack(); + table.act(Core.graphics.getDeltaTime()); + + Core.scene.add(table); + lastTable[0] = table; + }); + } + + + Label mode = new Label(""); + mode.setColor(Pal.remove); + mode.update(() -> mode.setText(tool.mode == -1 ? "" : "M" + (tool.mode + 1) + " ")); + mode.setAlignment(Align.bottomRight, Align.bottomRight); + mode.touchable(Touchable.disabled); + + tools.stack(button, mode); }; tools.defaults().size(size, size); @@ -479,14 +544,26 @@ public class MapEditorDialog extends Dialog implements Disposable{ } private void doInput(){ - //tool select - for(int i = 0; i < EditorTool.values().length; i++){ - if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){ - view.setTool(EditorTool.values()[i]); - break; + + if(Core.input.ctrl()){ + //alt mode select + //TODO these keycode are unusable, tweak later + for(int i = 0; i < view.getTool().altModes.length + 1; i++){ + if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){ + view.getTool().mode = i - 1; + } + } + }else{ + //tool select + for(int i = 0; i < EditorTool.values().length; i++){ + if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){ + view.setTool(EditorTool.values()[i]); + break; + } } } + if(Core.input.keyTap(KeyCode.ESCAPE)){ if(!menu.isShown()){ menu.show(); diff --git a/core/src/io/anuke/mindustry/editor/MapInfoDialog.java b/core/src/io/anuke/mindustry/editor/MapInfoDialog.java index b13abef7ea..1bfe9fad4c 100644 --- a/core/src/io/anuke/mindustry/editor/MapInfoDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapInfoDialog.java @@ -29,47 +29,49 @@ public class MapInfoDialog extends FloatingDialog{ cont.clear(); ObjectMap tags = editor.getTags(); + + cont.pane(t -> { + t.add("$editor.name").padRight(8).left(); + t.defaults().padTop(15); - cont.add("$editor.name").padRight(8).left(); + TextField name = t.addField(tags.get("name", ""), text -> { + tags.put("name", text); + }).size(400, 55f).get(); + name.setMessageText("$unknown"); - cont.defaults().padTop(15); + t.row(); + t.add("$editor.description").padRight(8).left(); - TextField name = cont.addField(tags.get("name", ""), text -> { - tags.put("name", text); - }).size(400, 55f).get(); - name.setMessageText("$unknown"); + TextArea description = t.addArea(tags.get("description", ""), "textarea", text -> { + tags.put("description", text); + }).size(400f, 140f).get(); - cont.row(); - cont.add("$editor.description").padRight(8).left(); + t.row(); + t.add("$editor.author").padRight(8).left(); - TextArea description = cont.addArea(tags.get("description", ""), "textarea", text -> { - tags.put("description", text); - }).size(400f, 140f).get(); + TextField author = t.addField(tags.get("author", Core.settings.getString("mapAuthor", "")), text -> { + tags.put("author", text); + Core.settings.put("mapAuthor", text); + Core.settings.save(); + }).size(400, 55f).get(); + author.setMessageText("$unknown"); - cont.row(); - cont.add("$editor.author").padRight(8).left(); + t.row(); + t.add("$editor.rules").padRight(8).left(); + t.addButton("$edit", () -> ruleInfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f); - TextField author = cont.addField(tags.get("author", Core.settings.getString("mapAuthor", "")), text -> { - tags.put("author", text); - Core.settings.put("mapAuthor", text); - Core.settings.save(); - }).size(400, 55f).get(); - author.setMessageText("$unknown"); + t.row(); + t.add("$editor.waves").padRight(8).left(); + t.addButton("$edit", waveInfo::show).left().width(200f); - cont.row(); - cont.add("$editor.rules").padRight(8).left(); - cont.addButton("$edit", () -> ruleInfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f); + name.change(); + description.change(); + author.change(); - cont.row(); - cont.add("$editor.waves").padRight(8).left(); - cont.addButton("$edit", waveInfo::show).left().width(200f); - - name.change(); - description.change(); - author.change(); - - Platform.instance.addDialog(name, 50); - Platform.instance.addDialog(author, 50); - Platform.instance.addDialog(description, 1000); + Platform.instance.addDialog(name, 50); + Platform.instance.addDialog(author, 50); + Platform.instance.addDialog(description, 1000); + t.margin(16f); + }); } } diff --git a/core/src/io/anuke/mindustry/editor/MapView.java b/core/src/io/anuke/mindustry/editor/MapView.java index a332dd3adc..79e141fe34 100644 --- a/core/src/io/anuke/mindustry/editor/MapView.java +++ b/core/src/io/anuke/mindustry/editor/MapView.java @@ -1,7 +1,6 @@ package io.anuke.mindustry.editor; import io.anuke.arc.Core; -import io.anuke.arc.collection.Array; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.GestureDetector; @@ -24,7 +23,6 @@ import static io.anuke.mindustry.Vars.ui; public class MapView extends Element implements GestureListener{ private MapEditor editor; private EditorTool tool = EditorTool.pencil; - private Bresenham2 br = new Bresenham2(); private float offsetx, offsety; private float zoom = 1f; private boolean grid = false; @@ -107,19 +105,8 @@ public class MapView extends Element implements GestureListener{ Point2 p = project(x, y); if(tool == EditorTool.line){ - if(Core.input.keyDown(KeyCode.TAB)){ - if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){ - p.y = firstTouch.y; - }else{ - p.x = firstTouch.x; - } - } - ui.editor.resetSaved(); - Array points = br.line(startx, starty, p.x, p.y); - for(Point2 point : points){ - editor.draw(point.x, point.y, EditorTool.isPaint()); - } + tool.touchedLine(editor, startx, starty, p.x, p.y); } editor.flushOp(); @@ -133,7 +120,6 @@ public class MapView extends Element implements GestureListener{ @Override public void touchDragged(InputEvent event, float x, float y, int pointer){ - mousex = x; mousey = y; @@ -141,13 +127,10 @@ public class MapView extends Element implements GestureListener{ if(drawing && tool.draggable && !(p.x == lastx && p.y == lasty)){ ui.editor.resetSaved(); - Array points = br.line(lastx, lasty, p.x, p.y); - for(Point2 point : points){ - tool.touched(editor, point.x, point.y); - } + Bresenham2.line(lastx, lasty, p.x, p.y, (cx, cy) -> tool.touched(editor, cx, cy)); } - if(tool == EditorTool.line && Core.input.keyDown(KeyCode.TAB)){ + if(tool == EditorTool.line && tool.mode == 1){ if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){ lastx = p.x; lasty = firstTouch.y; @@ -296,7 +279,13 @@ public class MapView extends Element implements GestureListener{ if((tool.edit || (tool == EditorTool.line && !drawing)) && (!mobile || drawing)){ Point2 p = project(mousex, mousey); Vector2 v = unproject(p.x, p.y).add(x, y); - Lines.poly(brushPolygons[index], v.x, v.y, scaling); + + //pencil square outline + if(tool == EditorTool.pencil && tool.mode == 1){ + Lines.square(v.x + scaling/2f, v.y + scaling/2f, scaling * (editor.brushSize + 0.5f)); + }else{ + Lines.poly(brushPolygons[index], v.x, v.y, scaling); + } } }else{ if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){ diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index eea9a3b82a..c80552996f 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -27,17 +27,8 @@ public class Net{ private static ObjectMap, BiConsumer> serverListeners = new ObjectMap<>(); private static ClientProvider clientProvider; private static ServerProvider serverProvider; - private static IntMap streams = new IntMap<>(); - public static boolean hasClient(){ - return clientProvider != null; - } - - public static boolean hasServer(){ - return serverProvider != null; - } - /** Display a network error. Call on the graphics thread. */ public static void showError(Throwable e){ @@ -50,12 +41,13 @@ public class Net{ String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase(); String type = t.getClass().toString().toLowerCase(); + boolean isError = false; if(e instanceof BufferUnderflowException || e instanceof BufferOverflowException){ error = Core.bundle.get("error.io"); }else if(error.equals("mismatch")){ error = Core.bundle.get("error.mismatch"); - }else if(error.contains("port out of range") || error.contains("invalid argument") || (error.contains("invalid") && error.contains("address"))){ + }else if(error.contains("port out of range") || error.contains("invalid argument") || (error.contains("invalid") && error.contains("address")) || Strings.parseException(e, true).contains("address associated")){ error = Core.bundle.get("error.invalidaddress"); }else if(error.contains("connection refused") || error.contains("route to host") || type.contains("unknownhost")){ error = Core.bundle.get("error.unreachable"); @@ -65,9 +57,14 @@ public class Net{ error = Core.bundle.get("error.alreadyconnected"); }else if(!error.isEmpty()){ error = Core.bundle.get("error.any") + "\n" + Strings.parseException(e, true); + isError = true; } - ui.showText("", Core.bundle.format("connectfail", error)); + if(isError){ + ui.showError(Core.bundle.format("connectfail", error)); + }else{ + ui.showText("", Core.bundle.format("connectfail", error)); + } ui.loadfrag.hide(); if(Net.client()){ diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 1c44841832..a274a08810 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -27,6 +27,8 @@ import io.anuke.mindustry.input.InputHandler.PlaceDraw; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.Bar; import io.anuke.mindustry.ui.ContentDisplay; +import io.anuke.mindustry.world.blocks.Floor; +import io.anuke.mindustry.world.blocks.OverlayFloor; import io.anuke.mindustry.world.consumers.*; import io.anuke.mindustry.world.meta.*; @@ -658,6 +660,18 @@ public class Block extends BlockStorage{ return buildVisibility.get() && !isHidden(); } + public boolean isFloor(){ + return this instanceof Floor; + } + + public boolean isOverlay(){ + return this instanceof OverlayFloor; + } + + public Floor asFloor(){ + return (Floor)this; + } + @Override public boolean isHidden(){ return !buildVisibility.get(); diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index cac7d27a7f..618d3cfc97 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -9,8 +9,7 @@ import io.anuke.mindustry.entities.traits.TargetTrait; import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.world.blocks.BlockPart; -import io.anuke.mindustry.world.blocks.Floor; +import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.modules.*; import static io.anuke.mindustry.Vars.*; @@ -161,6 +160,13 @@ public class Tile implements Position, TargetTrait{ this.overlay = 0; } + /** Sets the floor, preserving overlay.*/ + public void setFloorUnder(Floor floor){ + Block overlay = overlay(); + setFloor(floor); + setOverlay(overlay); + } + public byte rotation(){ return rotation; } @@ -190,7 +196,7 @@ public class Tile implements Position, TargetTrait{ } public void clearOverlay(){ - this.overlay = 0; + setOverlayID((short)0); } public boolean passable(){