diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index c9c76c4cca..6784100940 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -25,6 +25,7 @@ import mindustry.input.*; import mindustry.input.Placement.*; import mindustry.io.*; +import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.ConstructBlock.*; import mindustry.world.blocks.distribution.*; @@ -289,7 +290,9 @@ public FrameBuffer getBuffer(Schematic schematic){ /** Creates an array of build plans from a schematic's data, centered on the provided x+y coordinates. */ public Seq toPlans(Schematic schem, int x, int y){ return schem.tiles.map(t -> new BuildPlan(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block, t.config).original(t.x, t.y, schem.width, schem.height)) - .removeAll(s -> (!s.block.isVisible() && !(s.block instanceof CoreBlock) && !(s.block.name.matches("^(item|liquid)-(source|void)$"))) || !s.block.unlockedNow()).sort(Structs.comparingInt(s -> -s.block.schematicPriority)); + .removeAll(s -> (!s.block.isVisible() && !( + s.block instanceof CoreBlock || (s.block.buildVisibility == BuildVisibility.sandboxOnly && s.block.category != Category.defense /*Exclude walls*/) + )) || !s.block.unlockedNow()).sort(Structs.comparingInt(s -> -s.block.schematicPriority)); } /** @return all the valid loadouts for a specific core type. */ diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index d1d5e0ff90..09c6d78320 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -32,12 +32,14 @@ import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; import mindustry.ui.fragments.*; import mindustry.world.*; import mindustry.world.blocks.logic.*; import mindustry.world.blocks.payloads.*; +import mindustry.world.meta.*; import static arc.Core.*; import static mindustry.Vars.*; @@ -878,7 +880,7 @@ void pollInput(){ if(Core.input.keyTap(Binding.pause_building)){ if (Core.input.shift()) isFreezeQueueing = !isFreezeQueueing; else if (Core.input.ctrl()) { - Seq temp = frozenPlans.copy(); + temp.set(frozenPlans); flushPlans(temp, false, false, true); } else { @@ -909,7 +911,9 @@ else if (Core.input.ctrl()) { if(Core.input.keyDown(Binding.break_block)){ mode = none; }else if(selectPlans.any()){ - flushPlans(selectPlans, isFreezeQueueing, Core.input.keyDown(Binding.force_place_modifier), isFreezeQueueing); + flushPlans( + temp.selectFrom(selectPlans, s -> !(s.block.buildVisibility == BuildVisibility.sandboxOnly && s.block.category != Category.defense)), + isFreezeQueueing, Core.input.keyDown(Binding.force_place_modifier), isFreezeQueueing); }else if(isPlacing()){ selectX = cursorX; selectY = cursorY; diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 4db80cbf03..bd6aa5a249 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -90,6 +90,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public BuildPlan bplan = new BuildPlan(); public Seq linePlans = new Seq<>(); public Seq selectPlans = new Seq<>(BuildPlan.class); + protected Seq temp = new Seq<>(BuildPlan.class); public boolean conveyorPlaceNormal = false; /** Last logic virus warning block FINISHME: All the client stuff here is awful */ @Nullable public LogicBlock.LogicBuild lastVirusWarning, virusBuild; @@ -1367,7 +1368,8 @@ protected void flushSelectPlans(Seq plans){ private final Seq tempTiles = new Seq<>(4); protected void flushPlansReverse(Seq plans){ // FINISHME: Does this method work as intended? - flushPlans(plans.copy().reverse()); + temp.set(plans); + flushPlans(temp.reverse()); } public void flushPlans(Seq plans) { @@ -1631,47 +1633,38 @@ protected void freezeSelection(int x1, int y1, int x2, int y2, int maxLength){ freezeSelection(x1, y1, x2, y2, false, maxLength); } - /** Helper function with changing from the first Seq to the next. Used to be a BiPredicate but moved out **/ - private boolean checkFreezeSelectionHasNext(BuildPlan frz, Iterator it){ - boolean hasNext; - while((hasNext = it.hasNext()) && it.next() != frz) ; // skip to the next instance when it.next() == frz - if(hasNext) it.remove(); - return hasNext; - } - protected void freezeSelection(int x1, int y1, int x2, int y2, boolean flush, int maxLength){ NormalizeResult result = Placement.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength); - Seq tmpFrozenPlans = new Seq<>(); //remove build plans - Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize); + Rect r1 = Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize); + Rect r2 = Tmp.r2; + Seq frozenFromSelection = selectPlans.select(s -> s.bounds(r2).overlaps(r1)); + Seq frozenFromUnit = new Seq<>(BuildPlan.class); for(BuildPlan plan : player.unit().plans()){ - if(plan.bounds(Tmp.r2).overlaps(Tmp.r1)) tmpFrozenPlans.add(plan); - } - - for(BuildPlan plan : selectPlans){ - if(plan.bounds(Tmp.r2).overlaps(Tmp.r1)) tmpFrozenPlans.add(plan); + if(plan.bounds(r2).overlaps(r1)) frozenFromUnit.add(plan); } - Seq unfreeze = new Seq<>(); - for(BuildPlan plan : frozenPlans){ - if(plan.bounds(Tmp.r2).overlaps(Tmp.r1)) unfreeze.add(plan); - } + Seq unfreeze = temp.selectFrom(frozenPlans, s -> s.bounds(r2).overlaps(r1)); - if(unfreeze.size > tmpFrozenPlans.size) flushPlans(unfreeze, false, false, true); // Unfreeze the selection when there's more frozen blocks in the area + if(unfreeze.size > frozenFromUnit.size + frozenFromSelection.size) flushPlans(unfreeze, false, false, true); // Unfreeze the selection when there's more frozen blocks in the area else{ // If there's fewer frozen blocks than unfrozen ones, we freeze the selection - Iterator it1 = player.unit().plans().iterator(), it2 = selectPlans.iterator(); - for(BuildPlan frz : tmpFrozenPlans){ - if(checkFreezeSelectionHasNext(frz, it1)) continue; // Player plans contains frz: remove it and continue. - if(/*!itHasNext implied*/ it2 != null){ - it1 = it2; - it2 = null; // swap it2 into it1, continue iterating through without changing frz - if(checkFreezeSelectionHasNext(frz, it1)) continue; - } - break; // exit if there are no remaining items in the two Seq's to check. + // Remove plans from their original locations + Iterator it = player.unit().plans().iterator(); + boolean hasNext; + for(BuildPlan frz : frozenFromUnit){ + while((hasNext = it.hasNext()) && frz != it.next()); + if(hasNext) it.remove(); + else break; } - frozenPlans.addAll(tmpFrozenPlans); + it = selectPlans.iterator(); + for(BuildPlan frz : frozenFromSelection){ + while((hasNext = it.hasNext()) && frz != it.next()); + if(hasNext) it.remove(); + else break; + } + frozenPlans.addAll(frozenFromSelection).addAll(frozenFromUnit); } } @@ -1916,7 +1909,7 @@ public float mouseAngle(float x, float y){ ); if(unit != null){ unit.hitbox(Tmp.r1); - Tmp.r1.grow(input.shift() ? tilesize * 6 : 6f); // If shift is held, add 3 tiles of leeway, makes it easier to shift click units controlled by processors and such + Tmp.r1.grow(allowPlayers && input.shift() && !unit.isPlayer() ? tilesize * 6 : 6f); // If shift is held, add 3 tiles of leeway, makes it easier to shift click units controlled by processors and such if(Tmp.r1.contains(Core.input.mouseWorld())){ return unit; } diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 82f3a36ecb..5bb2a350ca 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -1121,19 +1121,20 @@ public static class Category extends Setting{ @Override public void add(SettingsTable table){ + ImageButton[] arrowButton = {null}; table.add("").row(); // Add a cell first as .row doesn't work if there are no cells in the current row. final Runnable onClicked = () -> { collapser.toggle(); settings.put("settingscategory-" + name + "-enabled", collapser.isCollapsed()); + arrowButton[0].getStyle().imageUp = collapser.isCollapsed() ? Icon.downOpen : Icon.upOpen; }; table.table(t -> { t.add(title).center().growX().color(Pal.accent).get().clicked(onClicked); - t.button(Icon.downOpen, style, onClicked) - .update(i -> i.getStyle().imageUp = (!collapser.isCollapsed() ? Icon.upOpen : Icon.downOpen)) - .size(10f).right().padRight(10f); + (arrowButton[0] = t.button(Icon.downOpen, style, onClicked).size(10f).right().padRight(10f).get()) + .getStyle().imageUp = collapser.isCollapsed() ? Icon.downOpen : Icon.upOpen; }).growX(); table.row(); - table.image(Tex.whiteui, Pal.accent).growX().height(3f).pad(4f); + table.image(Tex.whiteui, Pal.accent).growX().height(3f).padTop(4f).padBottom(4f); table.row(); table.add(collapser).left(); table.row(); diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 3d65fb37e4..baf34bd2e6 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -224,7 +224,7 @@ public void getPotentialLinks(Tile tile, Team team, Cons others){ } public void getPotentialLinks(Tile tile, Team team, Cons others, boolean skipExisting){ - getPotentialLinks(tile, team, others, true, true); + getPotentialLinks(tile, team, others, skipExisting, true); } public void getPotentialLinks(Tile tile, Team team, Cons others, boolean skipExisting, final boolean syncWithServer){