diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 846cd1b074..a9617ea0dd 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -277,6 +277,7 @@ filter.option.threshold = Threshold filter.option.circle-scale = Circle Scale filter.option.octaves = Octaves filter.option.falloff = Falloff +filter.option.angle = Angle filter.option.block = Block filter.option.floor = Floor filter.option.flooronto = Target Floor diff --git a/core/assets/maps/crags.msav b/core/assets/maps/crags.msav index 406168ec90..d3cb2b307a 100644 Binary files a/core/assets/maps/crags.msav and b/core/assets/maps/crags.msav differ diff --git a/core/assets/maps/impact0078.msav b/core/assets/maps/impact0078.msav index 6702c005db..872b26dc51 100644 Binary files a/core/assets/maps/impact0078.msav and b/core/assets/maps/impact0078.msav differ diff --git a/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java b/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java index 011c07d4d9..3a3dcc0ed4 100644 --- a/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java @@ -30,7 +30,8 @@ import static io.anuke.mindustry.Vars.*; public class MapGenerateDialog extends FloatingDialog{ private final Supplier[] filterTypes = new Supplier[]{ NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, - RiverNoiseFilter::new, OreFilter::new, MedianFilter::new, BlendFilter::new + RiverNoiseFilter::new, OreFilter::new, MedianFilter::new, BlendFilter::new, + MirrorFilter::new }; private final MapEditor editor; @@ -84,9 +85,19 @@ public class MapGenerateDialog extends FloatingDialog{ cont.clear(); cont.table(t -> { t.margin(8f); - t.stack(new BorderImage(texture){{ - setScaling(Scaling.fit); - }}, new Stack(){{ + t.stack(new BorderImage(texture){ + { + setScaling(Scaling.fit); + } + + @Override + public void draw(){ + super.draw(); + for(GenerateFilter filter : filters){ + filter.draw(this); + } + } + }, new Stack(){{ add(new Image("loadDim")); add(new Image("icon-refresh"){{ setScaling(Scaling.none); diff --git a/core/src/io/anuke/mindustry/editor/generation/FilterOption.java b/core/src/io/anuke/mindustry/editor/generation/FilterOption.java index 1ef160315e..3aa2441885 100644 --- a/core/src/io/anuke/mindustry/editor/generation/FilterOption.java +++ b/core/src/io/anuke/mindustry/editor/generation/FilterOption.java @@ -24,28 +24,32 @@ public abstract class FilterOption{ public abstract void build(Table table); - public Runnable changed = () -> { - }; + public Runnable changed = () -> {}; static class SliderOption extends FilterOption{ final String name; final FloatProvider getter; final FloatConsumer setter; - final float min, max; + final float min, max, step; SliderOption(String name, FloatProvider getter, FloatConsumer setter, float min, float max){ + this(name, getter, setter, min, max, (max - min) / 200); + } + + SliderOption(String name, FloatProvider getter, FloatConsumer setter, float min, float max, float step){ this.name = name; this.getter = getter; this.setter = setter; this.min = min; this.max = max; + this.step = step; } @Override public void build(Table table){ table.add("$filter.option." + name); table.row(); - Slider slider = table.addSlider(min, max, (max - min) / 200f, setter).growX().get(); + Slider slider = table.addSlider(min, max, step, setter).growX().get(); slider.setValue(getter.get()); if(updateEditorOnChange){ slider.changed(changed); diff --git a/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java b/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java index 9105a7b4e8..d06eb5fb82 100644 --- a/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java +++ b/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.editor.generation; import io.anuke.arc.Core; import io.anuke.arc.math.Mathf; +import io.anuke.arc.scene.ui.*; import io.anuke.arc.util.Pack; import io.anuke.arc.util.noise.RidgedPerlin; import io.anuke.arc.util.noise.Simplex; @@ -20,6 +21,9 @@ public abstract class GenerateFilter{ protected abstract void apply(); + //draw any additional guides + public void draw(Image image){} + protected float noise(float x, float y, float scl, float mag){ return (float)in.noise.octaveNoise2D(1f, 0f, 1f / scl, x + o, y + o) * mag; } diff --git a/core/src/io/anuke/mindustry/editor/generation/MirrorFilter.java b/core/src/io/anuke/mindustry/editor/generation/MirrorFilter.java new file mode 100644 index 0000000000..159225708e --- /dev/null +++ b/core/src/io/anuke/mindustry/editor/generation/MirrorFilter.java @@ -0,0 +1,69 @@ +package io.anuke.mindustry.editor.generation; + +import io.anuke.arc.function.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.math.geom.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.editor.MapGenerateDialog.*; +import io.anuke.mindustry.editor.generation.FilterOption.*; +import io.anuke.mindustry.graphics.*; + +import static io.anuke.mindustry.Vars.content; + +public class MirrorFilter extends GenerateFilter{ + private final Vector2 v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2(); + + float angle = 45; + + { + options(new SliderOption("angle", () -> angle, f -> angle = f, 0, 360, 45)); + } + + @Override + protected void apply(){ + v1.trns(angle - 90, 1f); + v2.set(v1).scl(-1f); + + v1.add(in.width/2f, in.height/2f); + v2.add(in.width/2f, in.height/2f); + + v3.set(in.x / in.scaling, in.y / in.scaling); + + if(!left(v1, v2, v3)){ + mirror(v3, v1.x, v1.y, v2.x, v2.y); + GenTile tile = in.tile(v3.x, v3.y); + in.floor = content.block(tile.floor); + in.block = content.block(tile.block); + in.ore = content.block(tile.ore); + } + } + + @Override + public void draw(Image image){ + super.draw(image); + float size = Math.max(image.getWidth() *2, image.getHeight()*2); + Consumer clamper = v -> v.clamp(image.getX(), image.getX() + image.getWidth(), image.getY(), image.getY() + image.getHeight()); + clamper.accept(Tmp.v1.trns(angle - 90, size).add(image.getWidth()/2f + image.getX(), image.getHeight()/2f + image.getY())); + clamper.accept(Tmp.v2.set(Tmp.v1).sub(image.getWidth()/2f + image.getX(), image.getHeight()/2f + image.getY()).rotate(180f).add(image.getWidth()/2f + image.getX(), image.getHeight()/2f + image.getY())); + + Lines.stroke(Unit.dp.scl(3f), Pal.accent); + Lines.line(Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y); + Draw.reset(); + } + + void mirror(Vector2 p, float x0, float y0, float x1, float y1){ + float dx = x1 - x0; + float dy = y1 - y0; + + float a = (dx * dx - dy * dy) / (dx * dx + dy*dy); + float b = 2 * dx * dy / (dx*dx + dy*dy); + + p.set((a * (p.x - x0) + b*(p.y - y0) + x0), (b * (p.x - x0) - a*(p.y - y0) + y0)); + } + + boolean left(Vector2 a, Vector2 b, Vector2 c){ + return ((b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x)) > 0; + } +} diff --git a/core/src/io/anuke/mindustry/type/Loadout.java b/core/src/io/anuke/mindustry/type/Loadout.java index b6a86bcb88..05339c3d1b 100644 --- a/core/src/io/anuke/mindustry/type/Loadout.java +++ b/core/src/io/anuke/mindustry/type/Loadout.java @@ -1,14 +1,12 @@ package io.anuke.mindustry.type; -import io.anuke.arc.collection.Array; -import io.anuke.arc.collection.IntMap; -import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.game.Content; +import io.anuke.arc.collection.*; +import io.anuke.mindustry.content.*; +import io.anuke.mindustry.game.*; import io.anuke.mindustry.world.*; -import io.anuke.mindustry.world.blocks.storage.CoreBlock; +import io.anuke.mindustry.world.blocks.storage.*; -import static io.anuke.mindustry.Vars.defaultTeam; -import static io.anuke.mindustry.Vars.world; +import static io.anuke.mindustry.Vars.*; public class Loadout extends Content{ private final Array outArray = new Array<>(); @@ -70,6 +68,8 @@ public class Loadout extends Content{ int rx = Pos.x(entry.key); int ry = Pos.y(entry.key); Tile tile = world.tile(x + rx, y + ry); + if(tile == null) continue; + world.setBlock(tile, entry.value.block, defaultTeam); tile.rotation((byte)entry.value.rotation); if(entry.value.ore != null){