diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 3075d76799..d8e89c826d 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -319,6 +319,7 @@ error.io = Network I/O error. error.any = Unknown network error. zone.groundZero.name = Ground Zero +zone.desertWastes.name = Desert Wastes zone.craters.name = The Craters zone.frozenForest.name = Frozen Forest zone.ruinousShores.name = Ruinous Shores diff --git a/core/src/io/anuke/mindustry/content/Zones.java b/core/src/io/anuke/mindustry/content/Zones.java index c989111c28..ea583c944f 100644 --- a/core/src/io/anuke/mindustry/content/Zones.java +++ b/core/src/io/anuke/mindustry/content/Zones.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.content; import io.anuke.mindustry.game.ContentList; import io.anuke.mindustry.game.Rules; +import io.anuke.mindustry.maps.generators.DesertWastesGenerator; import io.anuke.mindustry.maps.generators.MapGenerator; import io.anuke.mindustry.maps.generators.MapGenerator.Decoration; import io.anuke.mindustry.type.*; @@ -9,7 +10,7 @@ import io.anuke.mindustry.world.Block; public class Zones implements ContentList{ public static Zone - groundZero, desertThing, + groundZero, desertWastes, craters, frozenForest, ruinousShores, stainedMountains, overgrowth, infestedIslands, desolateRift, nuclearComplex; @@ -31,19 +32,18 @@ public class Zones implements ContentList{ }}; }}; - /* - desertThing = new Zone("desertThing", new DesertThingGenerator(240, 240)){{ + desertWastes = new Zone("desertWastes", new DesertWastesGenerator(260, 260)){{ startingItems = ItemStack.list(Items.copper, 200); - alwaysUnlocked = true; - conditionWave = 5; - launchPeriod = 5; - resources = new Item[]{Items.copper, Items.scrap, Items.lead}; + conditionWave = 10; + zoneRequirements = ZoneRequirement.with(groundZero, 10); + blockRequirements = new Block[]{Blocks.router}; + resources = new Item[]{Items.copper, Items.lead, Items.coal}; rules = () -> new Rules(){{ waves = true; waveTimer = true; - waveSpacing = 60 * 60 * 2; + waveSpacing = 60 * 60 * 1.5f; }}; - }};*/ + }}; craters = new Zone("craters", new MapGenerator("craters", 1).dist(0).decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{ startingItems = ItemStack.list(Items.copper, 200); diff --git a/core/src/io/anuke/mindustry/io/SaveIO.java b/core/src/io/anuke/mindustry/io/SaveIO.java index d39433142a..ad6231d118 100644 --- a/core/src/io/anuke/mindustry/io/SaveIO.java +++ b/core/src/io/anuke/mindustry/io/SaveIO.java @@ -3,7 +3,7 @@ package io.anuke.mindustry.io; import io.anuke.arc.collection.*; import io.anuke.arc.files.FileHandle; import io.anuke.mindustry.Vars; -import io.anuke.mindustry.io.versions.Save16; +import io.anuke.mindustry.io.versions.Save1; import java.io.*; import java.util.zip.DeflaterOutputStream; @@ -15,9 +15,7 @@ import static io.anuke.mindustry.Vars.*; public class SaveIO{ public static final IntArray breakingVersions = IntArray.with(47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 63); public static final IntMap versions = new IntMap<>(); - public static final Array versionArray = Array.with( - new Save16() - ); + public static final Array versionArray = Array.with(new Save1()); static{ for(SaveFileVersion version : versionArray){ diff --git a/core/src/io/anuke/mindustry/io/versions/Save16.java b/core/src/io/anuke/mindustry/io/versions/Save1.java similarity index 96% rename from core/src/io/anuke/mindustry/io/versions/Save16.java rename to core/src/io/anuke/mindustry/io/versions/Save1.java index 07549b53be..438da9feae 100644 --- a/core/src/io/anuke/mindustry/io/versions/Save16.java +++ b/core/src/io/anuke/mindustry/io/versions/Save1.java @@ -11,10 +11,10 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; -public class Save16 extends SaveFileVersion{ +public class Save1 extends SaveFileVersion{ - public Save16(){ - super(16); + public Save1(){ + super(1); } @Override diff --git a/core/src/io/anuke/mindustry/maps/generators/BasicGenerator.java b/core/src/io/anuke/mindustry/maps/generators/BasicGenerator.java index 687cbd9117..5b37a8f49c 100644 --- a/core/src/io/anuke/mindustry/maps/generators/BasicGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generators/BasicGenerator.java @@ -1,18 +1,26 @@ package io.anuke.mindustry.maps.generators; -import io.anuke.arc.collection.Array; +import io.anuke.arc.collection.*; +import io.anuke.arc.function.IntPositionConsumer; import io.anuke.arc.math.Mathf; +import io.anuke.arc.math.geom.Geometry; +import io.anuke.arc.math.geom.Point2; +import io.anuke.arc.util.Structs; import io.anuke.arc.util.noise.Simplex; import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.*; +import io.anuke.mindustry.world.blocks.Floor; -public class BasicGenerator extends RandomGenerator{ - private Array ores; - private Simplex sim = new Simplex(); - private Simplex sim2 = new Simplex(); +import java.util.PriorityQueue; - public BasicGenerator(int width, int height, Item... ores){ +public abstract class BasicGenerator extends RandomGenerator{ + protected static final DistanceHeuristic manhattan = (x1, y1, x2, y2) -> Math.abs(x1 - x2) + Math.abs(y1 - y2); + + protected Array ores; + protected Simplex sim = new Simplex(); + protected Simplex sim2 = new Simplex(); + + public BasicGenerator(int width, int height, Block... ores){ super(width, height); this.ores = Array.with(ores); } @@ -25,33 +33,189 @@ public class BasicGenerator extends RandomGenerator{ super.generate(tiles); } - @Override - public void generate(int x, int y){ - floor = Blocks.stone; + public void ores(Tile[][] tiles){ + pass(tiles, (x, y) -> { + if(ores != null){ + int offsetX = x - 4, offsetY = y + 23; + for(int i = ores.size - 1; i >= 0; i--){ + Block entry = ores.get(i); + if(Math.abs(0.5f - sim.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), offsetX, offsetY + i*999)) > 0.23f && + Math.abs(0.5f - sim2.octaveNoise2D(1, 1, 1f / (40 + i * 4), offsetX, offsetY - i*999)) > 0.32f){ + ore = entry; + break; + } + } + } + }); + } - if(ores != null){ - int offsetX = x - 4, offsetY = y + 23; - for(int i = ores.size - 1; i >= 0; i--){ - Item entry = ores.get(i); - if(Math.abs(0.5f - sim.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), offsetX, offsetY)) > 0.23f && - Math.abs(0.5f - sim2.octaveNoise2D(1, 1, 1f / (40 + i * 4), offsetX, offsetY)) > 0.32f){ + public void terrain(Tile[][] tiles, Block dst, float mag, float cmag){ + pass(tiles, (x, y) -> { + double rocks = sim.octaveNoise2D(5, 0.5, 1f / 60f, x, y) * mag + + Mathf.dst((float)x / width, (float)y / height, 0.5f, 0.5f) * cmag; - //floor = OreBlock.get(floor, entry); - break; + double edgeDist = Math.min(x, Math.min(y, Math.min(Math.abs(x - (width - 1)), Math.abs(y - (height - 1))))); + double transition = 5; + if(edgeDist < transition){ + rocks += (transition - edgeDist) / transition / 1.5; + } + + if(rocks > 0.9){ + block =dst; + } + }); + } + + public void noise(Tile[][] tiles, Block floor, Block block, int octaves, float falloff, float scl, float threshold){ + pass(tiles, (x, y) -> { + if(sim.octaveNoise2D(octaves, falloff, 1f / scl, x, y) > threshold){ + Tile tile = tiles[x][y]; + this.floor = floor; + if(tile.block().solid){ + this.block = block; + } + } + }); + } + + public void distort(Tile[][] tiles, float scl, float mag){ + Block[][] blocks = new Block[width][height]; + Floor[][] floors = new Floor[width][height]; + + each((x, y) -> { + float cx = x + noise(x, y, scl, mag) - mag / 2f, cy = y + noise(x, y + 1525215f, scl, mag) - mag / 2f; + Tile other = tiles[Mathf.clamp((int)cx, 0, width-1)][Mathf.clamp((int)cy, 0, height-1)]; + blocks[x][y] = other.block(); + floors[x][y] = other.floor(); + }); + + pass(tiles, (x, y) -> { + floor = floors[x][y]; + block = blocks[x][y]; + }); + } + + public void each(IntPositionConsumer r){ + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + r.accept(x, y); + } + } + } + + protected float noise(float x, float y, float scl, float mag){ + return (float)sim2.octaveNoise2D(1f, 0f, 1f / scl, x + 0x361266f, y + 0x251259f) * mag; + } + + public void pass(Tile[][] tiles, IntPositionConsumer r){ + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + floor = tiles[x][y].floor(); + block = tiles[x][y].block(); + ore = tiles[x][y].ore(); + r.accept(x, y); + tiles[x][y] = new Tile(x, y, floor.id, block.id); + tiles[x][y].setOre(ore); + } + } + } + + public void brush(Tile[][] tiles, Array path, int rad){ + path.each(tile -> erase(tiles, tile.x, tile.y, rad)); + } + + public void erase(Tile[][] tiles, int cx, int cy, int rad){ + for(int x = -rad; x <= rad; x++){ + for(int y = -rad; y <= rad; y++){ + int wx = cx + x, wy = cy + y; + if(Structs.inBounds(wx, wy, width, height) && Mathf.dst(x, y, 0, 0) <= rad){ + Tile other = tiles[wx][wy]; + other.setBlock(Blocks.air); + } + } + } + } + + public Array pathfind(Tile[][] tiles, int startX, int startY, int endX, int endY, TileHueristic th, DistanceHeuristic dh){ + Tile start = tiles[startX][startY]; + Tile end = tiles[endX][endY]; + GridBits closed = new GridBits(width, height); + IntFloatMap costs = new IntFloatMap(); + PriorityQueue queue = new PriorityQueue<>((a, b) -> Float.compare(costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y), costs.get(b.pos(), 0f) + dh.cost(b.x, b.y, end.x, end.y))); + queue.add(start); + boolean found = false; + while(!queue.isEmpty()){ + Tile next = queue.poll(); + float baseCost = costs.get(next.pos(), 0f); + if(next == end){ + found = true; + break; + } + closed.set(next.x, next.y); + for(Point2 point : Geometry.d4){ + int newx = next.x + point.x, newy = next.y + point.y; + if(Structs.inBounds(newx, newy, width, height)){ + Tile child = tiles[newx][newy]; + if(!closed.get(child.x, child.y)){ + closed.set(child.x, child.y); + child.setRotation(child.relativeTo(next.x, next.y)); + costs.put(child.pos(), th.cost(child) + baseCost); + queue.add(child); + } } } } - //rock outcrops - double rocks = sim.octaveNoise2D(3, 0.7, 1f / 70f, x, y); - double edgeDist = Math.min(x, Math.min(y, Math.min(Math.abs(x - (width - 1)), Math.abs(y - (height - 1))))); - double transition = 8; - if(edgeDist < transition){ - rocks += (transition - edgeDist) / transition / 1.5; + Array out = new Array<>(); + + if(!found) return out; + + Tile current = end; + while(current != start){ + out.add(current); + Point2 p = Geometry.d4(current.getRotation()); + current = tiles[current.x + p.x][current.y + p.y]; } - if(rocks > 0.64){ - block = Blocks.rocks; + out.reverse(); + + return out; + } + + public void inverseFloodFill(Tile[][] tiles, Tile start, Block block){ + IntArray arr = new IntArray(); + arr.add(start.pos()); + while(!arr.isEmpty()){ + int i = arr.pop(); + int x = Pos.x(i), y = Pos.y(i); + tiles[x][y].cost = 2; + for(Point2 point : Geometry.d4){ + int newx = x + point.x, newy = y + point.y; + if(Structs.inBounds(newx, newy, width, height)){ + Tile child = tiles[newx][newy]; + if(child.block() == Blocks.air && child.cost != 2){ + child.cost = 2; + arr.add(child.pos()); + } + } + } + } + + for(int x = 0; x < width; x ++){ + for(int y = 0; y < height; y++){ + Tile tile = tiles[x][y]; + if(tile.cost != 2 && tile.block() == Blocks.air){ + tile.setBlock(block); + } + } } } + + public interface DistanceHeuristic{ + float cost(int x1, int y1, int x2, int y2); + } + + public interface TileHueristic{ + float cost(Tile tile); + } } diff --git a/core/src/io/anuke/mindustry/maps/generators/DesertThingGenerator.java b/core/src/io/anuke/mindustry/maps/generators/DesertThingGenerator.java deleted file mode 100644 index 3a3b934694..0000000000 --- a/core/src/io/anuke/mindustry/maps/generators/DesertThingGenerator.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.anuke.mindustry.maps.generators; - -public class DesertThingGenerator extends RandomGenerator{ - - public DesertThingGenerator(int width, int height){ - super(width, height); - } - - @Override - public void generate(int x, int y){ - - } -} diff --git a/core/src/io/anuke/mindustry/maps/generators/DesertWastesGenerator.java b/core/src/io/anuke/mindustry/maps/generators/DesertWastesGenerator.java new file mode 100644 index 0000000000..8a58dcbf02 --- /dev/null +++ b/core/src/io/anuke/mindustry/maps/generators/DesertWastesGenerator.java @@ -0,0 +1,41 @@ +package io.anuke.mindustry.maps.generators; + +import io.anuke.arc.math.Mathf; +import io.anuke.mindustry.content.Blocks; +import io.anuke.mindustry.world.Tile; + +public class DesertWastesGenerator extends BasicGenerator{ + + public DesertWastesGenerator(int width, int height){ + super(width, height, Blocks.oreCopper, Blocks.oreLead, Blocks.oreCoal, Blocks.oreCopper); + } + + @Override + public void generate(int x, int y){ + floor = Blocks.sand; + } + + @Override + public void decorate(Tile[][] tiles){ + ores(tiles); + terrain(tiles, Blocks.sandRocks, 1.5f, 0.9f); + + int rand = 40; + int border = 25; + int spawnX = Mathf.clamp(30 + Mathf.range(rand), border, width - border), spawnY = Mathf.clamp(30 + Mathf.range(rand), border, height - border); + int endX = Mathf.clamp(width - 30 + Mathf.range(rand), border, width - border), endY = Mathf.clamp(height - 30 + Mathf.range(rand), border, height - border); + + brush(tiles, pathfind(tiles, spawnX, spawnY, endX, endY, tile -> tile.solid() ? 5f : 0f, manhattan), 6); + brush(tiles, pathfind(tiles, spawnX, spawnY, endX, endY, tile -> tile.solid() ? 4f : 0f + (float)sim.octaveNoise2D(1, 1, 1f / 40f, tile.x, tile.y) * 20, manhattan), 5); + + erase(tiles, endX, endY, 10); + erase(tiles, spawnX, spawnY, 20); + distort(tiles, 20f, 4f); + inverseFloodFill(tiles, tiles[spawnX][spawnY], Blocks.sandRocks); + + noise(tiles, Blocks.darksand, Blocks.duneRocks, 5, 0.7f, 120f, 0.5f); + + tiles[endX][endY].setBlock(Blocks.spawn); + loadout.setup(spawnX, spawnY); + } +} diff --git a/core/src/io/anuke/mindustry/maps/generators/Generator.java b/core/src/io/anuke/mindustry/maps/generators/Generator.java index f6bc16806d..965c6cf0e7 100644 --- a/core/src/io/anuke/mindustry/maps/generators/Generator.java +++ b/core/src/io/anuke/mindustry/maps/generators/Generator.java @@ -5,6 +5,7 @@ import io.anuke.mindustry.world.Tile; public abstract class Generator{ public int width, height; + protected Loadout loadout; public Generator(int width, int height){ this.width = width; @@ -15,7 +16,7 @@ public abstract class Generator{ } public void init(Loadout loadout){ - + this.loadout = loadout; } public abstract void generate(Tile[][] tiles); diff --git a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java index 96f9f9e0ce..df30a44239 100644 --- a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java @@ -26,7 +26,6 @@ public class MapGenerator extends Generator{ private Map map; private String mapName; private Array decorations = Array.with(new Decoration(Blocks.stone, Blocks.rock, 0.003f)); - private Loadout loadout; /** How much the landscape is randomly distorted. */ public float distortion = 3; /** diff --git a/core/src/io/anuke/mindustry/maps/generators/RandomGenerator.java b/core/src/io/anuke/mindustry/maps/generators/RandomGenerator.java index c7d07b9218..dc733ebd70 100644 --- a/core/src/io/anuke/mindustry/maps/generators/RandomGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generators/RandomGenerator.java @@ -1,13 +1,18 @@ package io.anuke.mindustry.maps.generators; +import io.anuke.arc.collection.ObjectMap; import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; +import static io.anuke.mindustry.Vars.customMapDirectory; +import static io.anuke.mindustry.Vars.world; + public abstract class RandomGenerator extends Generator{ protected Block floor; protected Block block; + protected Block ore; public RandomGenerator(int width, int height){ super(width, height); @@ -19,15 +24,20 @@ public abstract class RandomGenerator extends Generator{ for(int y = 0; y < height; y++){ floor = Blocks.air; block = Blocks.air; + ore = Blocks.air; generate(x, y); tiles[x][y] = new Tile(x, y, floor.id, block.id); + tiles[x][y].setOre(ore); } } - tiles[width / 2][height / 2].setBlock(Blocks.coreShard, Team.blue); - tiles[width / 2][height / 2 - 6].setBlock(Blocks.launchPad, Team.blue); + decorate(tiles); + + world.setMap(new Map(customMapDirectory.child("generated"), 0, 0, new ObjectMap<>(), true)); } + public abstract void decorate(Tile[][] tiles); + /** * Sets {@link #floor} and {@link #block} to the correct values as output. * Before this method is called, both are set to {@link Blocks#air} as defaults.