From c083d059c99d47e36507431c88bdd9856ead89aa Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 11 Mar 2019 08:25:03 -0400 Subject: [PATCH] Progress --- core/src/io/anuke/mindustry/core/World.java | 24 +- .../io/anuke/mindustry/editor/MapEditor.java | 1 - core/src/io/anuke/mindustry/io/MapIO.java | 325 +++++++++--------- .../anuke/mindustry/io/SaveFileVersion.java | 2 + core/src/io/anuke/mindustry/maps/Map.java | 14 +- .../maps/generators/MapGenerator.java | 166 +++++---- core/src/io/anuke/mindustry/world/Tile.java | 10 + 7 files changed, 263 insertions(+), 279 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index 8a8cfe1251..440e0562d0 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -22,6 +22,7 @@ import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; +import io.anuke.mindustry.maps.MapException; import io.anuke.mindustry.maps.Maps; import io.anuke.mindustry.maps.generators.Generator; import io.anuke.mindustry.type.ContentType; @@ -232,12 +233,10 @@ public class World implements ApplicationListener{ beginMapLoad(); this.currentMap = map; - int width = map.meta.width, height = map.meta.height; - - createTiles(width, height); - try{ - loadTileData(tiles, MapIO.readTileData(map, true)); + createTiles(map.width, map.height); + tiles = MapIO.readTiles(map, tiles); + prepareTiles(tiles); }catch(Exception e){ Log.err(e); if(!headless){ @@ -257,7 +256,7 @@ public class World implements ApplicationListener{ if(state.teams.get(players[0].getTeam()).cores.size == 0){ ui.showError("$map.nospawn"); invalidMap = true; - }else if(state.rules.pvp){ //pvp maps need two cores to be valid + }else if(state.rules.pvp){ //pvp maps need two cores to be valid invalidMap = true; for(Team team : Team.all){ if(state.teams.get(team).cores.size != 0 && team != players[0].getTeam()){ @@ -413,18 +412,7 @@ public class World implements ApplicationListener{ } /**Loads raw map tile data into a Tile[][] array, setting up multiblocks, cliffs and ores. */ - void loadTileData(Tile[][] tiles, MapTileData data){ - data.position(0, 0); - TileDataMarker marker = data.newDataMarker(); - - for(int y = 0; y < data.height(); y++){ - for(int x = 0; x < data.width(); x++){ - data.read(marker); - - tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.part.id ? 0 : marker.wall, marker.rotation, marker.team); - } - } - + void loadTileData(Tile[][] tiles){ prepareTiles(tiles); } diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index cb5aabeb19..bb5f4a24ec 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -6,7 +6,6 @@ import io.anuke.arc.util.Pack; import io.anuke.arc.util.Structs; import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.editor.DrawOperation.TileOperation; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index 7216e315aa..b736f83c6b 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -1,38 +1,31 @@ package io.anuke.mindustry.io; -import io.anuke.arc.collection.IntIntMap; import io.anuke.arc.collection.ObjectMap; import io.anuke.arc.collection.ObjectMap.Entry; import io.anuke.arc.files.FileHandle; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Pixmap; -import io.anuke.arc.graphics.Pixmap.Format; import io.anuke.arc.util.Pack; -import io.anuke.arc.util.Structs; import io.anuke.mindustry.content.Blocks; +import io.anuke.mindustry.game.MappableContent; import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.game.Version; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapMeta; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.DataPosition; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; -import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.LegacyColorMapper; -import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock; +import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.blocks.BlockPart; import java.io.*; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; import static io.anuke.mindustry.Vars.content; +import static io.anuke.mindustry.Vars.world; -/** - * Reads and writes map files. - */ -//TODO name mapping +/** Reads and writes map files.*/ public class MapIO{ + private static final int version = 1; private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; - private static final int version = 0; - private static IntIntMap defaultBlockMap = new IntIntMap(); public static boolean isImage(FileHandle file){ try(InputStream stream = file.read()){ @@ -47,161 +40,21 @@ public class MapIO{ } } - private static void loadDefaultBlocks(){ - for(Block block : content.blocks()){ - defaultBlockMap.put(block.id, block.id); - } + //TODO implement + public static Pixmap unfinished_generatePreview(Map map){ + return null; } - public static Pixmap generatePixmap(MapTileData data){ - Pixmap pixmap = new Pixmap(data.width(), data.height(), Format.RGBA8888); - data.position(0, 0); - - TileDataMarker marker = data.newDataMarker(); - - for(int y = 0; y < data.height(); y++){ - for(int x = 0; x < data.width(); x++){ - data.read(marker); - Block floor = content.block(marker.floor); - Block wall = content.block(marker.wall); - int color = colorFor(floor, wall, Team.all[marker.team]); - pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, color); - } - } - - data.position(0, 0); - - return pixmap; + //TODO implement + /**Reads a pixmap in the 3.5 pixmap format.*/ + public static Tile[][] unfinished_readLegacyPixmap(Pixmap pixmap){ + return null; } - /**Reads a pixmap in the old (3.5) map format.*/ - public static MapTileData readLegacyPixmap(Pixmap pixmap){ - MapTileData data = new MapTileData(pixmap.getWidth(), pixmap.getHeight()); - - for(int x = 0; x < data.width(); x++){ - for(int y = 0; y < data.height(); y++){ - int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); - LegacyBlock block = LegacyColorMapper.get(color); - - data.write(x, y, DataPosition.floor, block.floor.id); - data.write(x, y, DataPosition.wall, block.wall.id); - - //place core - if(color == Color.rgba8888(Color.GREEN)){ - for(int dx = 0; dx < 3; dx++){ - for(int dy = 0; dy < 3; dy++){ - int worldx = dx - 1 + x; - int worldy = dy - 1 + y; - - if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){ - data.write(worldx, worldy, DataPosition.wall, Blocks.part.id); - data.write(worldx, worldy, DataPosition.rotationTeam, Pack.byteByte((byte)0, (byte)Team.blue.ordinal())); - data.write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx - 1 + 8), (byte) (dy - 1 + 8))); - } - } - } - - data.write(x, y, DataPosition.wall, Blocks.coreShard.id); - data.write(x, y, DataPosition.rotationTeam, Pack.byteByte((byte)0, (byte)Team.blue.ordinal())); - } - } - } - - return data; - } - - public static void writeMap(OutputStream stream, ObjectMap tags, MapTileData data) throws IOException{ - if(defaultBlockMap == null){ - loadDefaultBlocks(); - } - - MapMeta meta = new MapMeta(version, tags, data.width(), data.height(), defaultBlockMap); - - DataOutputStream ds = new DataOutputStream(stream); - - writeMapMeta(ds, meta); - ds.write(data.toArray()); - - ds.close(); - } - - /** - * Reads tile data, skipping meta. - */ - public static MapTileData readTileData(DataInputStream stream, boolean readOnly) throws IOException{ - MapMeta meta = readMapMeta(stream); - return readTileData(stream, meta, readOnly); - } - - - /** - * Does not skip meta. Call after reading meta. - */ - public static MapTileData readTileData(DataInputStream stream, MapMeta meta, boolean readOnly) throws IOException{ - byte[] bytes = new byte[stream.available()]; - stream.readFully(bytes); - return new MapTileData(bytes, meta.width, meta.height, meta.blockMap, readOnly); - } - - /** - * Reads tile data, skipping meta tags. - */ - public static MapTileData readTileData(Map map, boolean readOnly){ - try(DataInputStream ds = new DataInputStream(map.stream.get())){ - return MapIO.readTileData(ds, readOnly); - }catch(IOException e){ - throw new RuntimeException(e); - } - } - - public static MapMeta readMapMeta(DataInputStream stream) throws IOException{ - ObjectMap tags = new ObjectMap<>(); - IntIntMap map = new IntIntMap(); - - int version = stream.readInt(); - - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - String name = stream.readUTF(); - String value = stream.readUTF(); - tags.put(name, value); - } - - short blocks = stream.readShort(); - for(int i = 0; i < blocks; i++){ - short id = stream.readShort(); - String name = stream.readUTF(); - Block block = content.getByName(ContentType.block, name); - if(block == null){ - block = Blocks.air; - } - map.put(id, block.id); - } - - int width = stream.readShort(); - int height = stream.readShort(); - - return new MapMeta(version, tags, width, height, map); - } - - public static void writeMapMeta(DataOutputStream stream, MapMeta meta) throws IOException{ - stream.writeInt(meta.version); - stream.writeByte((byte) meta.tags.size); - - for(Entry entry : meta.tags.entries()){ - stream.writeUTF(entry.key); - stream.writeUTF(entry.value); - } - - stream.writeShort(content.blocks().size); - for(Block block : content.blocks()){ - stream.writeShort(block.id); - stream.writeUTF(block.name); - } - - stream.writeShort(meta.width); - stream.writeShort(meta.height); + //TODO implement + /**Reads a pixmap in the old 4.0 .mmap format.*/ + private static Tile[][] unfinished_readLegacyMmap(InputStream stream) throws IOException{ + return null; } public static int colorFor(Block floor, Block wall, Team team){ @@ -210,4 +63,140 @@ public class MapIO{ } return Color.rgba8888(wall.solid ? wall.color : floor.color); } -} + + public static void writeMap(Map map, Tile[][] tiles, OutputStream output) throws IOException{ + try(DataOutputStream stream = new DataOutputStream(output)){ + stream.writeInt(version); + stream.writeInt(Version.build); + stream.writeShort(tiles.length); + stream.writeShort(tiles[0].length); + stream.writeByte((byte)map.tags.size); + + for(Entry entry : map.tags.entries()){ + stream.writeUTF(entry.key); + stream.writeUTF(entry.value); + } + } + + try(DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(output))){ + + SaveIO.getSaveWriter().writeContentHeader(stream); + + stream.writeShort(tiles.length); + stream.writeShort(tiles[0].length); + + //TODO 2-phase rle + for(int i = 0; i < tiles.length * tiles[0].length; i++){ + Tile tile = world.tile(i % world.width(), i / world.width()); + + stream.writeByte(tile.getFloorID()); + stream.writeByte(tile.getBlockID()); + stream.writeByte(tile.getOre()); + + if(tile.block() instanceof BlockPart){ + stream.writeByte(tile.link); + }else if(tile.entity != null){ + stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation + stream.writeShort((short)tile.entity.health); //health + tile.entity.writeConfig(stream); + }else if(tile.block() == Blocks.air){ + int consecutives = 0; + + for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ + Tile nextTile = world.tile(j % world.width(), j / world.width()); + + if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getOre() != tile.getOre()){ + break; + } + + consecutives++; + } + + stream.writeByte(consecutives); + i += consecutives; + } + } + } + } + + public static Map readMap(String useName, InputStream input) throws IOException{ + try(DataInputStream stream = new DataInputStream(input)){ + ObjectMap tags = new ObjectMap<>(); + + //meta is uncompressed + int version = stream.readInt(); + int build = stream.readInt(); + short width = stream.readShort(), height = stream.readShort(); + byte tagAmount = stream.readByte(); + + for(int i = 0; i < tagAmount; i++){ + String name = stream.readUTF(); + String value = stream.readUTF(); + tags.put(name, value); + } + + return new Map(useName, width, height); + } + } + + public static Tile[][] readTiles(Map map, Tile[][] tiles) throws IOException{ + return readTiles(map.stream.get(), map.width, map.height, tiles); + } + + public static Tile[][] readTiles(InputStream input, int width, int height, Tile[][] tiles) throws IOException{ + readMap("this map name is utterly irrelevant", input); + + try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){ + + MappableContent[][] c = SaveIO.getSaveWriter().readContentHeader(stream); + + try{ + content.setTemporaryMapper(c); + //TODO 2-phase rle + + for(int i = 0; i < width * height; i++){ + int x = i % width, y = i / width; + byte floorid = stream.readByte(); + byte wallid = stream.readByte(); + byte oreid = stream.readByte(); + + Tile tile = new Tile(x, y, floorid, wallid); + + if(wallid == Blocks.part.id){ + tile.link = stream.readByte(); + }else if(tile.entity != null){ + byte tr = stream.readByte(); + short health = stream.readShort(); + + byte team = Pack.leftByte(tr); + byte rotation = Pack.rightByte(tr); + + tile.setTeam(Team.all[team]); + tile.entity.health = health; + tile.setRotation(rotation); + + tile.entity.readConfig(stream); + }else if(wallid == 0){ + int consecutives = stream.readUnsignedByte(); + + for(int j = i + 1; j < i + 1 + consecutives; j++){ + int newx = j % width, newy = j / width; + Tile newTile = new Tile(newx, newy, floorid, wallid); + newTile.setOre(oreid); + tiles[newx][newy] = newTile; + } + + i += consecutives; + } + + tiles[x][y] = tile; + } + + return tiles; + + }finally{ + content.setTemporaryMapper(null); + } + } + } +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/io/SaveFileVersion.java b/core/src/io/anuke/mindustry/io/SaveFileVersion.java index e304816eef..fe0c646c09 100644 --- a/core/src/io/anuke/mindustry/io/SaveFileVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveFileVersion.java @@ -42,6 +42,7 @@ public abstract class SaveFileVersion{ return new SaveMeta(version, time, playtime, build, map, wave, rules); } + //TODO 2-phase rle public void writeMap(DataOutputStream stream) throws IOException{ //write world size @@ -86,6 +87,7 @@ public abstract class SaveFileVersion{ } } + //TODO 2-phase rle public void readMap(DataInputStream stream) throws IOException{ short width = stream.readShort(); short height = stream.readShort(); diff --git a/core/src/io/anuke/mindustry/maps/Map.java b/core/src/io/anuke/mindustry/maps/Map.java index bc61e67049..46c034ba64 100644 --- a/core/src/io/anuke/mindustry/maps/Map.java +++ b/core/src/io/anuke/mindustry/maps/Map.java @@ -16,18 +16,22 @@ public class Map{ public final ObjectMap tags; /** Supplies a new input stream with the data of this map.*/ public final Supplier stream; + /**Map width/height, shorts.*/ + public int width, height; /** Preview texture.*/ public Texture texture; - public Map(String name, ObjectMap tags, boolean custom, Supplier streamSupplier){ + public Map(String name, int width, int height, ObjectMap tags, boolean custom, Supplier streamSupplier){ this.name = name; this.custom = custom; this.tags = tags; this.stream = streamSupplier; + this.width = width; + this.height = height; } - public Map(String name){ - this(name, new ObjectMap<>(), true, () -> null); + public Map(String name, int width, int height){ + this(name, width, height, new ObjectMap<>(), true, () -> null); } public String getDisplayName(){ @@ -50,10 +54,6 @@ public class Map{ return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Core.bundle.get("unknown"); } - public boolean hasOreGen(){ - return !tags.get("oregen", "0").equals("0"); - } - @Override public String toString(){ return "Map{" + diff --git a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java index c083662278..9367e7673a 100644 --- a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java @@ -9,8 +9,6 @@ import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Items; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.Loadout; import io.anuke.mindustry.world.Block; @@ -21,8 +19,9 @@ import io.anuke.mindustry.world.blocks.StaticWall; import io.anuke.mindustry.world.blocks.storage.CoreBlock; import io.anuke.mindustry.world.blocks.storage.StorageBlock; -import static io.anuke.mindustry.Vars.content; -import static io.anuke.mindustry.Vars.world; +import java.io.IOException; + +import static io.anuke.mindustry.Vars.*; public class MapGenerator extends Generator{ private Map map; @@ -73,112 +72,109 @@ public class MapGenerator extends Generator{ public void init(Loadout loadout){ this.loadout = loadout; map = world.maps.loadInternalMap(mapName); - width = map.meta.width; - height = map.meta.height; + width = map.width; + height = map.height; } @Override public void generate(Tile[][] tiles){ - MapTileData data = MapIO.readTileData(map, true); + try{ + MapIO.readTiles(map, tiles); + Array players = new Array<>(); + Array enemies = new Array<>(); - data.position(0, 0); - TileDataMarker marker = data.newDataMarker(); - Array players = new Array<>(); - Array enemies = new Array<>(); + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + if(tiles[x][y].block() instanceof CoreBlock){ + players.add(new Point2(x, y)); + tiles[x][y].setBlock(Blocks.air); + } - for(int y = 0; y < data.height(); y++){ - for(int x = 0; x < data.width(); x++){ - data.read(marker); - - if(content.block(marker.wall) instanceof CoreBlock){ - players.add(new Point2(x, y)); - marker.wall = 0; + if(tiles[x][y].block() == Blocks.spawn){ + enemies.add(new Point2(x, y)); + tiles[x][y].setBlock(Blocks.air); + } } - - if(enemySpawns != -1 && content.block(marker.wall) == Blocks.spawn){ - enemies.add(new Point2(x, y)); - marker.wall = 0; - } - - tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.part.id ? 0 : marker.wall, marker.rotation, marker.team); } - } - Simplex simplex = new Simplex(Mathf.random(99999)); + Simplex simplex = new Simplex(Mathf.random(99999)); - for(int x = 0; x < data.width(); x++){ - for(int y = 0; y < data.height(); y++){ - final double scl = 10; - Tile tile = tiles[x][y]; - int newX = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x, y) * distortion + x), 0, data.width()-1); - int newY = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x + 9999, y + 9999) * distortion + y), 0, data.height()-1); + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + final double scl = 10; + Tile tile = tiles[x][y]; + int newX = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x, y) * distortion + x), 0, width - 1); + int newY = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x + 9999, y + 9999) * distortion + y), 0, height - 1); - if((tile.block() instanceof StaticWall + if((tile.block() instanceof StaticWall && tiles[newX][newY].block() instanceof StaticWall) || (tile.block() == Blocks.air && !tiles[newX][newY].block().synthetic()) || (tiles[newX][newY].block() == Blocks.air && tile.block() instanceof StaticWall)){ - tile.setBlock(tiles[newX][newY].block()); - } - - if(distortFloor){ - tile.setFloor(tiles[newX][newY].floor()); - } - - for(Decoration decor : decorations){ - if(tile.block() == Blocks.air && !(decor.wall instanceof Floor) && tile.floor() == decor.floor && Mathf.chance(decor.chance)){ - tile.setBlock(decor.wall); - }else if(tile.floor() == decor.floor && decor.wall instanceof Floor && Mathf.chance(decor.chance)){ - tile.setFloor((Floor)decor.wall); + tile.setBlock(tiles[newX][newY].block()); } - } - if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){ - for(ItemStack stack : storageDrops){ - if(Mathf.chance(0.3)){ - tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); + if(distortFloor){ + tile.setFloor(tiles[newX][newY].floor()); + } + + for(Decoration decor : decorations){ + if(tile.block() == Blocks.air && !(decor.wall instanceof Floor) && tile.floor() == decor.floor && Mathf.chance(decor.chance)){ + tile.setBlock(decor.wall); + }else if(tile.floor() == decor.floor && decor.wall instanceof Floor && Mathf.chance(decor.chance)){ + tile.setFloor((Floor)decor.wall); } } - } - } - } - if(enemySpawns != -1){ - if(enemySpawns > enemies.size){ - throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number."); - } - - enemies.shuffle(); - for(int i = 0; i < enemySpawns; i++){ - Point2 point = enemies.get(i); - tiles[point.x][point.y].setBlock(Blocks.spawn); - - int rad = 10, frad = 12; - - for(int x = -rad; x <= rad; x++){ - for(int y = -rad; y <= rad; y++){ - int wx = x + point.x, wy = y + point.y; - double dst = Mathf.dst(x, y); - if(dst < frad && Structs.inBounds(wx, wy, tiles) && (dst <= rad || Mathf.chance(0.5))){ - Tile tile = tiles[wx][wy]; - if(tile.floor() instanceof OreBlock){ - OreBlock block = (OreBlock)tile.floor(); - tile.setFloor(block.base); + if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){ + for(ItemStack stack : storageDrops){ + if(Mathf.chance(0.3)){ + tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); } } } } } + + if(enemySpawns != -1){ + if(enemySpawns > enemies.size){ + throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number."); + } + + enemies.shuffle(); + for(int i = 0; i < enemySpawns; i++){ + Point2 point = enemies.get(i); + tiles[point.x][point.y].setBlock(Blocks.spawn); + + int rad = 10, frad = 12; + + for(int x = -rad; x <= rad; x++){ + for(int y = -rad; y <= rad; y++){ + int wx = x + point.x, wy = y + point.y; + double dst = Mathf.dst(x, y); + if(dst < frad && Structs.inBounds(wx, wy, tiles) && (dst <= rad || Mathf.chance(0.5))){ + Tile tile = tiles[wx][wy]; + if(tile.floor() instanceof OreBlock){ + OreBlock block = (OreBlock)tile.floor(); + tile.setFloor(block.base); + } + } + } + } + } + } + + Point2 core = players.random(); + if(core == null){ + throw new IllegalArgumentException("All zone maps must have a core."); + } + + loadout.setup(core.x, core.y); + + world.prepareTiles(tiles); + world.setMap(map); + }catch(IOException e){ + throw new RuntimeException(e); } - - Point2 core = players.random(); - if(core == null){ - throw new IllegalArgumentException("All zone maps must have a core."); - } - - loadout.setup(core.x, core.y); - - world.prepareTiles(tiles); - world.setMap(map); } public static class Decoration{ diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index 5bc7e46926..b60897e1e6 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -39,6 +39,8 @@ public class Tile implements Position, TargetTrait{ private byte rotation; /** Team ordinal. */ private byte team; + /**Ore that is on top of this (floor) block.*/ + private byte ore; public Tile(int x, int y){ this.x = (short) x; @@ -316,6 +318,14 @@ public class Tile implements Position, TargetTrait{ return getTeam() == Team.none || team == getTeam(); } + public byte getOre(){ + return ore; + } + + public void setOre(byte ore){ + this.ore = ore; + } + public void updateOcclusion(){ cost = 1; boolean occluded = false;