diff --git a/core/assets-raw/sprites/blocks/environment/thorium1.png b/core/assets-raw/sprites/blocks/environment/thorium1.png index 80d5f306f2..181d5a2c99 100644 Binary files a/core/assets-raw/sprites/blocks/environment/thorium1.png and b/core/assets-raw/sprites/blocks/environment/thorium1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/thorium2.png b/core/assets-raw/sprites/blocks/environment/thorium2.png index cd87190ec9..dade930e34 100644 Binary files a/core/assets-raw/sprites/blocks/environment/thorium2.png and b/core/assets-raw/sprites/blocks/environment/thorium2.png differ diff --git a/core/assets-raw/sprites/blocks/environment/thorium3.png b/core/assets-raw/sprites/blocks/environment/thorium3.png index 32c1841e0e..1485d7638e 100644 Binary files a/core/assets-raw/sprites/blocks/environment/thorium3.png and b/core/assets-raw/sprites/blocks/environment/thorium3.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index b0e64b7658..0faf77a349 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -151,8 +151,8 @@ text.editor.generate=Generate text.editor.resize=Resize text.editor.loadmap=Load Map text.editor.savemap=Save Map -text.editor.loadimage=Load Image -text.editor.saveimage=Save Image +text.editor.loadimage=Import Terrain +text.editor.saveimage=Export Terrain text.editor.unsaved=[scarlet]You have unsaved changes![]\nAre you sure you want to exit? text.editor.brushsize=Brush size: {0} text.editor.noplayerspawn=This map has no player spawnpoint! diff --git a/core/assets/maps/test.mmap b/core/assets/maps/test.mmap index d64e3155c4..2cd4660f8c 100644 Binary files a/core/assets/maps/test.mmap and b/core/assets/maps/test.mmap differ diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index f7841e4bc9..d5f0fc323c 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/assets/version.properties b/core/assets/version.properties index 6a04ece8a7..1f05cc61e5 100644 --- a/core/assets/version.properties +++ b/core/assets/version.properties @@ -1,7 +1,7 @@ #Autogenerated file. Do not modify. -#Sat Mar 24 18:18:45 EDT 2018 +#Sun Mar 25 00:43:28 EDT 2018 version=release -androidBuildCode=635 +androidBuildCode=638 name=Mindustry code=3.4 build=custom build diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 33560d66e6..4b899f6994 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -87,7 +87,7 @@ public class Logic extends Module { world.pathfinder().update(); - if(world.getAllyCores().size == 0 && !state.gameOver && false){ //TODO gameover state + if(world.getAllyCores().size == 0 && !state.gameOver){ //TODO gameover state state.gameOver = true; if(Net.server()) NetEvents.handleGameOver(); Events.fire(GameOverEvent.class); diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index e5efff01f9..f7a0c405c0 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -179,7 +179,7 @@ public class World extends Module{ Entities.resizeTree(0, 0, width * tilesize, height * tilesize); - WorldGenerator.generate(tiles, MapIO.readTileData(map)); + WorldGenerator.generate(tiles, MapIO.readTileData(map), allyCores); } void set(int x, int y, Block type, int rot){ diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index 09d25c573d..67d0bca6b1 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.editor; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapTileData; import io.anuke.mindustry.io.MapTileData.TileDataMarker; import io.anuke.mindustry.world.Block; @@ -16,6 +17,7 @@ public class MapEditor{ private int brushSize = 1; private Block drawBlock = Blocks.stone; + private Team drawTeam = Team.none; public MapEditor(){ @@ -31,7 +33,15 @@ public class MapEditor{ this.brushSize = 1; renderer.resize(map.width(), map.height()); } - + + public void setDrawTeam(Team team){ + this.drawTeam = team; + } + + public Team getDrawTeam() { + return drawTeam; + } + public Block getDrawBlock(){ return drawBlock; } @@ -60,6 +70,10 @@ public class MapEditor{ writer.wall = (byte)drawBlock.id; } + if(drawBlock.hasEntity()){ + writer.team = (byte)drawTeam.ordinal(); + } + for(int rx = -brushSize + 1; rx <= brushSize - 1; rx ++){ for(int ry = -brushSize + 1; ry <= brushSize - 1; ry ++){ if(Mathf.dst(rx, ry) <= brushSize){ diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 1f56b427fe..7b9a9bb2cf 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -3,8 +3,10 @@ package io.anuke.mindustry.editor; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.ObjectMap; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.io.MapTileData; import io.anuke.mindustry.io.Platform; @@ -18,6 +20,7 @@ import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Graphics; import io.anuke.ucore.core.Inputs; import io.anuke.ucore.core.Timers; +import io.anuke.ucore.graphics.Pixmaps; import io.anuke.ucore.scene.Element; import io.anuke.ucore.scene.actions.Actions; import io.anuke.ucore.scene.builders.build; @@ -42,7 +45,7 @@ public class MapEditorDialog extends Dialog{ private MapResizeDialog resizeDialog; private ScrollPane pane; private FloatingDialog menu; - private FileChooser openFile, saveFile; + private FileChooser openFile, saveFile, openImage, saveImage; private ObjectMap tags = new ObjectMap<>(); private boolean saved = false; @@ -56,7 +59,7 @@ public class MapEditorDialog extends Dialog{ dialog = new MapGenerateDialog(editor); view = new MapView(editor); - saveFile = new FileChooser("$saveimage", false, file -> { + saveFile = new FileChooser("$text.saveimage", false, file -> { file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension); FileHandle result = file; ui.loadfrag.show(); @@ -88,6 +91,38 @@ public class MapEditorDialog extends Dialog{ }); }); + saveImage = new FileChooser("$text.saveimage", false, file -> { + file = file.parent().child(file.nameWithoutExtension() + ".png"); + FileHandle result = file; + ui.loadfrag.show(); + Timers.run(3f, () -> { + + try{ + Pixmaps.write(MapIO.generatePixmap(editor.getMap()), result); + }catch (Exception e){ + ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false))); + Log.err(e); + } + ui.loadfrag.hide(); + }); + }); + + openImage = new FileChooser("$text.loadimage", FileChooser.pngFilter, true, file -> { + ui.loadfrag.show(); + Timers.run(3f, () -> { + try{ + MapTileData data = MapIO.readPixmap(new Pixmap(file)); + + editor.beginEdit(data); + view.clearStack(); + }catch (Exception e){ + ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); + Log.err(e); + } + ui.loadfrag.hide(); + }); + }); + menu = new FloatingDialog("$text.menu"); menu.addCloseButton(); @@ -118,6 +153,19 @@ public class MapEditorDialog extends Dialog{ menu.hide(); }); + menu.content().row(); + + menu.content().addImageTextButton("$text.editor.saveimage", "icon-save-map", isize, () -> { + saveImage.show(); + menu.hide(); + }); + + menu.content().row(); + + menu.content().addImageTextButton("$text.editor.loadimage", "icon-load-map", isize, () -> { + openImage.show(); + menu.hide(); + }); /* @@ -284,7 +332,22 @@ public class MapEditorDialog extends Dialog{ if (tool == EditorTool.pencil) button.setChecked(true); - tools.add(button).padBottom(-6f); + tools.add(button).padBottom(-5.1f); + if(i++ % 2 == 1) tools.row(); + } + + ButtonGroup teamgroup = new ButtonGroup<>(); + + for(Team team : Team.values()){ + ImageButton button = new ImageButton("white", "toggle"); + button.margin(4f, 4f, 10f, 4f); + button.getImageCell().grow(); + button.getStyle().imageUpColor = team.color; + button.clicked(() -> editor.setDrawTeam(team)); + button.update(() -> button.setChecked(editor.getDrawTeam() == team)); + teamgroup.add(button); + tools.add(button).padBottom(-5.1f); + if(i++ % 2 == 1) tools.row(); } @@ -351,44 +414,9 @@ public class MapEditorDialog extends Dialog{ } } - private boolean verifyMap(){ - //TODO make sure both teams have cores or something - /* - int psc = ColorMapper.getColor(SpecialBlocks.playerSpawn); - int esc = ColorMapper.getColor(SpecialBlocks.enemySpawn); - - int playerSpawns = 0; - int enemySpawns = 0; - Pixmap pix = editor.pixmap(); - - for(int x = 0; x < pix.getWidth(); x ++){ - for(int y = 0; y < pix.getHeight(); y ++){ - int i = pix.getPixel(x, y); - if(i == psc) playerSpawns ++; - if(i == esc) enemySpawns ++; - } - } - - if(playerSpawns == 0){ - ui.showError("$text.editor.noplayerspawn"); - return false; - }else if(playerSpawns > 1){ - ui.showError("$text.editor.manyplayerspawns"); - return false; - } - - if(enemySpawns > MapEditor.maxSpawnpoints){ - ui.showError(Bundles.format("text.editor.manyenemyspawns", MapEditor.maxSpawnpoints)); - return false; - }*/ - - return true; - } - private void addBlockSelection(Table table){ Table content = new Table(); pane = new ScrollPane(content, "volume"); - //pane.setScrollingDisabled(true, false); pane.setFadeScrollBars(false); pane.setOverscroll(true, false); ButtonGroup group = new ButtonGroup<>(); diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java new file mode 100644 index 0000000000..c3aeda7618 --- /dev/null +++ b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java @@ -0,0 +1,25 @@ +package io.anuke.mindustry.entities.units; + +import io.anuke.mindustry.entities.Unit; +import io.anuke.ucore.graphics.Draw; + +public class FlyingUnitType extends UnitType { + + public FlyingUnitType(String name) { + super(name); + } + + @Override + public void draw(BaseUnit unit) { + Draw.alpha(unit.hitTime / Unit.hitDuration); + + Draw.rect(name, unit.x, unit.y, unit.rotation); + + Draw.alpha(1f); + } + + @Override + public void behavior(BaseUnit unit) { + + } +} diff --git a/core/src/io/anuke/mindustry/game/Team.java b/core/src/io/anuke/mindustry/game/Team.java index 6662c15090..1a4bad572a 100644 --- a/core/src/io/anuke/mindustry/game/Team.java +++ b/core/src/io/anuke/mindustry/game/Team.java @@ -5,7 +5,8 @@ import com.badlogic.gdx.graphics.Color; public enum Team { none(Color.DARK_GRAY), blue(Color.ROYAL), - red(Color.valueOf("e84737")); + red(Color.valueOf("e84737")), + green(Color.valueOf("1dc645")); public final Color color; diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index 209b996b46..01901baff0 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -9,6 +9,8 @@ import com.badlogic.gdx.utils.ObjectMap.Entry; import io.anuke.mindustry.io.MapTileData.TileDataMarker; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.ColorMapper; +import io.anuke.mindustry.world.ColorMapper.BlockPair; +import io.anuke.mindustry.world.blocks.Blocks; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -25,6 +27,7 @@ public class MapIO { public static Pixmap generatePixmap(MapTileData data){ Pixmap pixmap = new Pixmap(data.width(), data.height(), Format.RGBA8888); + data.position(0, 0); for(int x = 0; x < data.width(); x ++){ for(int y = 0; y < data.height(); y ++){ @@ -39,6 +42,31 @@ public class MapIO { return pixmap; } + public static MapTileData readPixmap(Pixmap pixmap){ + MapTileData data = new MapTileData(pixmap.getWidth(), pixmap.getHeight()); + + data.position(0, 0); + TileDataMarker marker = data.getMarker(); + + for(int x = 0; x < data.width(); x ++){ + for(int y = 0; y < data.height(); y ++){ + BlockPair pair = ColorMapper.get(pixmap.getPixel(y, pixmap.getWidth() - 1 - x)); + + if(pair == null){ + marker.floor = (byte)Blocks.stone.id; + marker.wall = (byte)Blocks.air.id; + }else{ + marker.floor = (byte)pair.floor.id; + marker.wall = (byte)pair.wall.id; + } + + data.write(); + } + } + + return data; + } + public static void writeMap(FileHandle file, ObjectMap tags, MapTileData data) throws IOException{ MapMeta meta = new MapMeta(version, tags, data.width(), data.height()); diff --git a/core/src/io/anuke/mindustry/io/MapTileData.java b/core/src/io/anuke/mindustry/io/MapTileData.java index 84e45841c2..ee2d4cd944 100644 --- a/core/src/io/anuke/mindustry/io/MapTileData.java +++ b/core/src/io/anuke/mindustry/io/MapTileData.java @@ -39,6 +39,10 @@ public class MapTileData { return height; } + public TileDataMarker getMarker() { + return tile; + } + /**Reads and returns the next tile data.*/ public TileDataMarker read(){ tile.read(buffer); @@ -52,6 +56,11 @@ public class MapTileData { return tile; } + /**Writes and returns the next tile data.*/ + public void write(){ + tile.write(buffer); + } + /**Writes tile data at a specified position.*/ public void write(int x, int y, TileDataMarker writer){ position(x, y); diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 514b4e98bb..0a6e14b397 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -220,6 +220,10 @@ public class Block extends BaseBlock { region.setRegionHeight(8); return region; } + + public boolean hasEntity(){ + return destructible || update; + } public TileEntity getEntity(){ return new TileEntity(); diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index f5dea32ab5..a0c68f0b11 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -305,7 +305,7 @@ public class Tile{ Block block = block(); - if (block.destructible || block.update) { + if (block.hasEntity()) { entity = block.getEntity().init(this, block.update); if(block.hasInventory) entity.inventory = new InventoryModule(); if(block.hasLiquids) entity.liquid = new LiquidModule(); diff --git a/core/src/io/anuke/mindustry/world/WorldGenerator.java b/core/src/io/anuke/mindustry/world/WorldGenerator.java index 7fa1c10335..d4ed1516b1 100644 --- a/core/src/io/anuke/mindustry/world/WorldGenerator.java +++ b/core/src/io/anuke/mindustry/world/WorldGenerator.java @@ -1,11 +1,13 @@ package io.anuke.mindustry.world; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.ObjectMap; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapTileData; import io.anuke.mindustry.io.MapTileData.TileDataMarker; import io.anuke.mindustry.world.blocks.Blocks; +import io.anuke.mindustry.world.blocks.ProductionBlocks; import io.anuke.ucore.noise.Noise; import static io.anuke.mindustry.Vars.world; @@ -20,7 +22,7 @@ public class WorldGenerator { }}; /**Should fill spawns with the correct spawnpoints.*/ - public static void generate(Tile[][] tiles, MapTileData data){ + public static void generate(Tile[][] tiles, MapTileData data, Array cores){ Noise.setSeed(world.getSeed()); IntArray multiblocks = new IntArray(); @@ -34,6 +36,10 @@ public class WorldGenerator { multiblocks.add(tiles[x][y].packedPosition()); } + if(tiles[x][y].block() == ProductionBlocks.core){ + cores.add(tiles[x][y]); + } + //TODO ores, plants, extra decoration? } } diff --git a/core/src/io/anuke/mindustry/world/blocks/types/production/UnitFactory.java b/core/src/io/anuke/mindustry/world/blocks/types/production/UnitFactory.java index 7ca4cd833d..825b3d1184 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/production/UnitFactory.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/production/UnitFactory.java @@ -1,14 +1,80 @@ package io.anuke.mindustry.world.blocks.types.production; +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.entities.units.BaseUnit; import io.anuke.mindustry.entities.units.UnitType; +import io.anuke.mindustry.resource.ItemStack; import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.blocks.types.modules.InventoryModule; +import io.anuke.ucore.core.Timers; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; public class UnitFactory extends Block { protected UnitType type; + protected ItemStack[] requirements; + protected float produceTime = 1000f; + protected float powerUse = 0.1f; public UnitFactory(String name) { super(name); + solid = true; + update = true; + hasPower = true; } + @Override + public void update(Tile tile) { + UnitFactoryEntity entity = tile.entity(); + float used = Math.min(powerUse * Timers.delta(), powerCapacity); + + if(hasRequirements(entity.inventory, entity.buildTime/produceTime) && + entity.power.amount >= used){ + + entity.buildTime += Timers.delta(); + entity.power.amount -= used; + + if(entity.buildTime >= produceTime){ + BaseUnit unit = new BaseUnit(type, tile.getTeam()); + unit.set(tile.drawx(), tile.drawy()); + entity.buildTime = 0f; + + for(ItemStack stack : requirements){ + entity.inventory.removeItem(stack.item, stack.amount); + } + } + } + } + + @Override + public TileEntity getEntity() { + return new UnitFactoryEntity(); + } + + protected boolean hasRequirements(InventoryModule inv, float fraction){ + for(ItemStack stack : requirements){ + if(!inv.hasItem(stack.item, (int)(fraction * stack.amount))){ + return false; + } + } + return true; + } + + public static class UnitFactoryEntity extends TileEntity{ + public float buildTime; + + @Override + public void write(DataOutputStream stream) throws IOException { + stream.writeFloat(buildTime); + } + + @Override + public void read(DataInputStream stream) throws IOException { + buildTime = stream.readFloat(); + } + } }