diff --git a/android/assets/sprites/back.png b/android/assets/sprites/back.png index 9a2c29bc0f..70a6cf360a 100644 Binary files a/android/assets/sprites/back.png and b/android/assets/sprites/back.png differ diff --git a/android/assets/sprites/conveyort.png b/android/assets/sprites/conveyort.png index afb9ebd8c7..c5a360ac40 100644 Binary files a/android/assets/sprites/conveyort.png and b/android/assets/sprites/conveyort.png differ diff --git a/core/src/io/anuke/mindustry/Control.java b/core/src/io/anuke/mindustry/Control.java index 41bc46c61d..1999dde58b 100644 --- a/core/src/io/anuke/mindustry/Control.java +++ b/core/src/io/anuke/mindustry/Control.java @@ -400,6 +400,7 @@ public class Control extends RendererModule{ AndroidInput.mousex = Gdx.graphics.getWidth()/2; AndroidInput.mousey = Gdx.graphics.getHeight()/2; + camera.position.set(player.x, player.y, 0); } } diff --git a/core/src/io/anuke/mindustry/UI.java b/core/src/io/anuke/mindustry/UI.java index d6df72dd97..9226b492a8 100644 --- a/core/src/io/anuke/mindustry/UI.java +++ b/core/src/io/anuke/mindustry/UI.java @@ -76,10 +76,13 @@ public class UI extends SceneModule{ int tw = w/64+1; - batch.draw(Textures.get("back"), 0, 0, 0, 0, w, h); + float scale = Unit.dp.inPixels(1f); + + batch.draw(Textures.get("back"), 0, 0, w, h, 0, 0, (float)w/h/scale * h/Textures.get("back").getHeight()/4f, -1f/scale * h/Textures.get("back").getHeight()/4f); for(int x = 0; x < tw; x ++){ - batch.draw(Textures.get("conveyort"), x*64, 0, 0, (int)(Timers.time()*2*(x%2-0.5f)), 32, h); + float offset = (Timers.time()*2*(x%2-0.5f))/32f; + batch.draw(Textures.get("conveyort"), x*64*scale, 0, 32*scale, h*scale, 0, offset, 1, h/32 + offset); } Draw.color(); diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 12394df315..ea42a84d33 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -20,6 +20,8 @@ public class Vars{ public static boolean debug = false; + public static final int saveSlots = 4; + //turret and enemy shoot speed inverse multiplier public static final int multiplier = android ? 3 : 1; diff --git a/core/src/io/anuke/mindustry/io/SaveIO.java b/core/src/io/anuke/mindustry/io/SaveIO.java index 1731b9e69f..6d11d19c6c 100644 --- a/core/src/io/anuke/mindustry/io/SaveIO.java +++ b/core/src/io/anuke/mindustry/io/SaveIO.java @@ -3,9 +3,13 @@ package io.anuke.mindustry.io; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.reflect.ClassReflection; import io.anuke.mindustry.Inventory; @@ -23,6 +27,11 @@ import io.anuke.ucore.entities.Entity; /* * Save format: * + * --META-- + * + * Save file version ID (int) + * Last saved timestamp (long) + * * --STATE DATA-- * Wave (int) * Wave countdown time (float) @@ -67,6 +76,11 @@ import io.anuke.ucore.entities.Entity; * */ public class SaveIO{ + /**Save file version ID. Should be incremented every breaking release.*/ + private static final int fileVersionID = 0; + + private static final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss"); + //TODO automatic registration of types? private static final ObjectMap, Byte> enemyIDs = new ObjectMap, Byte>(){{ put(Enemy.class, (byte)0); @@ -80,10 +94,36 @@ public class SaveIO{ put(enemyIDs.get(value), value); }}; + public static boolean isSaveValid(int slot){ + try(DataInputStream stream = new DataInputStream(fileFor(slot).read())){ + return stream.readInt() == fileVersionID; + }catch (Exception e){ + return false; + } + } + + public static String getTimeString(int slot){ + + try(DataInputStream stream = new DataInputStream(fileFor(slot).read())){ + stream.readInt(); + Date date = new Date(stream.readLong()); + return format.format(date); + }catch (IOException e){ + throw new RuntimeException(e); + } + } + + public static FileHandle fileFor(int slot){ + return Gdx.files.local("mindustry-saves/" + slot + ".mins"); + } + public static void write(FileHandle file){ try(DataOutputStream stream = new DataOutputStream(file.write(false))){ + stream.writeInt(fileVersionID); //version id + stream.writeLong(TimeUtils.millis()); + //--GENERAL STATE-- stream.writeInt(Vars.control.getWave()); //wave stream.writeFloat(Vars.control.getWaveCountdown()); //wave countdown @@ -188,6 +228,13 @@ public class SaveIO{ try(DataInputStream stream = new DataInputStream(file.read())){ Item[] itemEnums = Item.values(); + int version = stream.readInt(); + /*long loadTime = */stream.readLong(); + + if(version != fileVersionID){ + //TODO throw an exception? + } + //general state int wave = stream.readInt(); diff --git a/core/src/io/anuke/mindustry/ui/MenuDialog.java b/core/src/io/anuke/mindustry/ui/MenuDialog.java index a8bf1ae648..be7660ba42 100644 --- a/core/src/io/anuke/mindustry/ui/MenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/MenuDialog.java @@ -4,11 +4,13 @@ import static io.anuke.mindustry.Vars.ui; import io.anuke.mindustry.GameState; import io.anuke.mindustry.GameState.State; +import io.anuke.mindustry.Vars; import io.anuke.ucore.scene.ui.ConfirmDialog; import io.anuke.ucore.scene.ui.Dialog; import io.anuke.ucore.scene.ui.layout.Unit; public class MenuDialog extends Dialog{ + private SaveDialog save = new SaveDialog(); public MenuDialog(){ super("Paused", "dialog"); @@ -16,20 +18,34 @@ public class MenuDialog extends Dialog{ } void setup(){ + content().defaults().width(200).units(Unit.dp); + content().addButton("Back", ()->{ hide(); GameState.set(State.playing); - }).width(200).units(Unit.dp); + }); content().row(); content().addButton("Settings", ()->{ ui.showPrefs(); - }).width(200).units(Unit.dp); + }); + + if(!Vars.android){ + content().row(); + content().addButton("Controls", ()->{ + ui.showControls(); + }); + } content().row(); - content().addButton("Controls", ()->{ - ui.showControls(); - }).width(200).units(Unit.dp); + content().addButton("Save Game", ()->{ + save.show(); + }); + + content().row(); + content().addButton("Load Game", ()->{ + + }); content().row(); content().addButton("Back to menu", ()->{ @@ -37,6 +53,6 @@ public class MenuDialog extends Dialog{ hide(); GameState.set(State.menu); }).show(); - }).width(200).units(Unit.dp); + }); } } diff --git a/core/src/io/anuke/mindustry/ui/SaveDialog.java b/core/src/io/anuke/mindustry/ui/SaveDialog.java new file mode 100644 index 0000000000..f532b8740b --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/SaveDialog.java @@ -0,0 +1,39 @@ +package io.anuke.mindustry.ui; + +import io.anuke.mindustry.Vars; +import io.anuke.mindustry.io.SaveIO; +import io.anuke.ucore.scene.ui.Dialog; +import io.anuke.ucore.scene.ui.TextButton; +import io.anuke.ucore.scene.ui.layout.Unit; + +public class SaveDialog extends Dialog{ + + public SaveDialog() { + super("Save Game"); + setup(); + } + + private void setup(){ + content().clear(); + + content().add("Select a save slot.").padBottom(4); + content().row(); + + for(int i = 0; i < Vars.saveSlots; i ++){ + TextButton button = new TextButton("[yellow]Slot " + i); + button.getLabelCell().top().left().growX(); + button.row(); + button.pad(12); + button.add("[gray]" + (!SaveIO.isSaveValid(i) ? "" : "Last Saved: " + SaveIO.getTimeString(i))); + button.getLabel().setFontScale(1f); + + button.clicked(()->{ + + }); + + content().add(button).size(400, 100).units(Unit.dp).pad(10); + content().row(); + } + } + +}