Added new save file format system, wall balancing

This commit is contained in:
Anuken
2018-01-02 15:47:08 -05:00
parent 4b69f5b41c
commit 2796ab9801
25 changed files with 939 additions and 529 deletions

View File

@@ -11,7 +11,6 @@ import io.anuke.kryonet.KryoClient;
import io.anuke.kryonet.KryoServer; import io.anuke.kryonet.KryoServer;
import io.anuke.mindustry.io.PlatformFunction; import io.anuke.mindustry.io.PlatformFunction;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.scene.ui.layout.Unit;
@@ -56,18 +55,17 @@ public class AndroidLauncher extends AndroidApplication{
} }
@Override @Override
public void onSceneChange(String state, String details, String icon) { public void onSceneChange(String state, String details, String icon) { }
}
@Override @Override
public void onGameExit() { public void onGameExit() { }
@Override
public void openDonations() {
showDonations();
} }
}; };
Mindustry.donationsCallable = new Callable(){ @Override public void run(){ showDonations(); } };
if(doubleScaleTablets && isTablet(this.getContext())){ if(doubleScaleTablets && isTablet(this.getContext())){
Unit.dp.addition = 0.5f; Unit.dp.addition = 0.5f;
} }

View File

@@ -4,17 +4,15 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.I18NBundle; import com.badlogic.gdx.utils.I18NBundle;
import com.badlogic.gdx.utils.OrderedMap;
import io.anuke.mindustry.core.*; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.io.PlatformFunction; import io.anuke.mindustry.io.PlatformFunction;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.BlockLoader;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.ucore.UCore;
import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Inputs; import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.modules.ModuleCore; import io.anuke.ucore.modules.ModuleCore;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
@@ -22,7 +20,6 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
public class Mindustry extends ModuleCore { public class Mindustry extends ModuleCore {
public static Callable donationsCallable;
public static boolean hasDiscord = true; public static boolean hasDiscord = true;
public static Array<String> args = new Array<>(); public static Array<String> args = new Array<>();
public static PlatformFunction platforms = new PlatformFunction(){ public static PlatformFunction platforms = new PlatformFunction(){
@@ -31,14 +28,17 @@ public class Mindustry extends ModuleCore {
@Override public void openLink(String link){ } @Override public void openLink(String link){ }
@Override public void addDialog(TextField field){} @Override public void addDialog(TextField field){}
@Override public void onSceneChange(String state, String details, String icon) {} @Override public void onSceneChange(String state, String details, String icon) {}
@Override public void onGameExit() { } @Override public void onGameExit() {}
@Override public void openDonations() {}
}; };
public static OrderedMap<String, Integer> idMap = new OrderedMap<>();
public static boolean externalBundle = false; public static boolean externalBundle = false;
@Override @Override
public void init(){ public void init(){
loadBundle(); loadBundle();
BlockLoader.load();
module(Vars.world = new World()); module(Vars.world = new World());
module(Vars.control = new Control()); module(Vars.control = new Control());
@@ -68,24 +68,12 @@ public class Mindustry extends ModuleCore {
Locale locale = Locale.getDefault(); Locale locale = Locale.getDefault();
Core.bundle = I18NBundle.createBundle(handle, locale); Core.bundle = I18NBundle.createBundle(handle, locale);
} }
//always initialize blocks in this order, otherwise there are ID errors
Block[] blockClasses = {
Blocks.air,
DefenseBlocks.compositewall,
DistributionBlocks.conduit,
ProductionBlocks.coaldrill,
WeaponBlocks.chainturret,
SpecialBlocks.enemySpawn
};
UCore.log("Block classes: " + blockClasses.length);
} }
@Override @Override
public void postInit(){ public void postInit(){
Vars.control.reset(); Vars.control.reset();
Vars.control.getSaves().convertSaves();
} }
@Override @Override

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.core;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.compression.Lzma;
import com.badlogic.gdx.utils.reflect.ClassReflection; import com.badlogic.gdx.utils.reflect.ClassReflection;
import com.badlogic.gdx.utils.reflect.ReflectionException; import com.badlogic.gdx.utils.reflect.ReflectionException;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
@@ -27,6 +28,8 @@ import io.anuke.ucore.entities.BaseBulletType;
import io.anuke.ucore.entities.Entity; import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.modules.Module; import io.anuke.ucore.modules.Module;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@@ -76,8 +79,16 @@ public class NetClient extends Module {
Net.handle(WorldData.class, data -> { Net.handle(WorldData.class, data -> {
Gdx.app.postRunnable(() -> { Gdx.app.postRunnable(() -> {
ByteArrayOutputStream outc = new ByteArrayOutputStream();
try {
Lzma.decompress(data.stream, outc);
}catch (IOException e){
throw new RuntimeException(e);
}
UCore.log("Recieved world data: " + data.stream.available() + " bytes."); UCore.log("Recieved world data: " + data.stream.available() + " bytes.");
NetworkIO.load(data.stream); NetworkIO.load(new ByteArrayInputStream(outc.toByteArray()));
Vars.player.set(Vars.control.core.worldx(), Vars.control.core.worldy() - Vars.tilesize*2); Vars.player.set(Vars.control.core.worldx(), Vars.control.core.worldy() - Vars.tilesize*2);
GameState.set(State.playing); GameState.set(State.playing);

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.compression.Lzma;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.BulletType; import io.anuke.mindustry.entities.BulletType;
@@ -56,8 +57,19 @@ public class NetServer extends Module{
UCore.log("Packed " + stream.size() + " uncompressed bytes of data."); UCore.log("Packed " + stream.size() + " uncompressed bytes of data.");
ByteArrayInputStream inc = new ByteArrayInputStream(stream.toByteArray());
ByteArrayOutputStream outc = new ByteArrayOutputStream();
try {
Lzma.compress(inc, outc);
}catch (IOException e){
throw new RuntimeException(e);
}
UCore.log("Packed " + outc.size() + " COMPRESSED bytes of data.");
//TODO compress and uncompress when sending //TODO compress and uncompress when sending
data.stream = new ByteArrayInputStream(stream.toByteArray()); data.stream = new ByteArrayInputStream(outc.toByteArray());
Net.sendStream(id, data); Net.sendStream(id, data);

View File

@@ -53,8 +53,6 @@ public class UI extends SceneModule{
Tooltip tooltip; Tooltip tooltip;
Tile configTile; Tile configTile;
MapEditor editor; MapEditor editor;
String lastip = "localhost";
int lastport = Vars.port;
boolean wasPaused = false; boolean wasPaused = false;
private Fragment menufrag = new MenuFragment(), private Fragment menufrag = new MenuFragment(),

View File

@@ -5,7 +5,8 @@ import io.anuke.ucore.core.Settings;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
public class EnemySpawn{ public class EnemySpawn{
private static float[] scalings = {2f, 1.5f, 1f}; /**Scaling multiplier for each difficulty. Easy, normal, hard.*/
private static float[] scalings = {4f, 2.5f, 1.5f};
/**The enemy type spawned*/ /**The enemy type spawned*/
public final Class<? extends Enemy> type; public final Class<? extends Enemy> type;

View File

@@ -16,9 +16,8 @@ import io.anuke.ucore.entities.Entities;
import java.io.*; import java.io.*;
import static io.anuke.mindustry.Vars.android; import static io.anuke.mindustry.io.SaveFileVersion.enemyIDs;
import static io.anuke.mindustry.io.SaveIO.enemyIDs; import static io.anuke.mindustry.io.SaveFileVersion.idEnemies;
import static io.anuke.mindustry.io.SaveIO.idEnemies;
public class NetworkIO { public class NetworkIO {
private static final int fileVersionID = 13; private static final int fileVersionID = 13;

View File

@@ -1,9 +1,9 @@
package io.anuke.mindustry.io; package io.anuke.mindustry.io;
import java.util.Date;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
import java.util.Date;
public interface PlatformFunction{ public interface PlatformFunction{
public String format(Date date); public String format(Date date);
public String format(int number); public String format(int number);
@@ -11,4 +11,5 @@ public interface PlatformFunction{
public void addDialog(TextField field); public void addDialog(TextField field);
public void onSceneChange(String state, String details, String icon); public void onSceneChange(String state, String details, String icon);
public void onGameExit(); public void onGameExit();
public void openDonations();
} }

View File

@@ -0,0 +1,49 @@
package io.anuke.mindustry.io;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.entities.enemies.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public abstract class SaveFileVersion {
public static final Array<Class<? extends Enemy>> enemyIDs = Array.with(
Enemy.class,
FastEnemy.class,
RapidEnemy.class,
FlamerEnemy.class,
TankEnemy.class,
BlastEnemy.class,
MortarEnemy.class,
TestEnemy.class,
HealerEnemy.class,
TitanEnemy.class,
EmpEnemy.class
);
public static final ObjectMap<Class<? extends Enemy>, Byte> idEnemies = new ObjectMap<Class<? extends Enemy>, Byte>(){{
for(int i = 0; i < enemyIDs.size; i ++){
put(enemyIDs.get(i), (byte)i);
}
}};
public final int version;
public SaveFileVersion(int version){
this.version = version;
}
public SaveMeta getData(DataInputStream stream) throws IOException{
int version = stream.readInt(); //read version
long time = stream.readLong(); //read last saved time
byte mode = stream.readByte(); //read the gamemode
byte map = stream.readByte(); //read the map
int wave = stream.readInt(); //read the wave
return new SaveMeta(version, time, mode, map, wave);
}
public abstract void read(DataInputStream stream) throws IOException;
public abstract void write(DataOutputStream stream) throws IOException;
}

View File

@@ -1,110 +1,21 @@
package io.anuke.mindustry.io; package io.anuke.mindustry.io;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Base64Coder; import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.OrderedMap;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.Mindustry;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.enemies.*; import io.anuke.mindustry.io.versions.Save12;
import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.io.versions.Save13;
import io.anuke.mindustry.resource.Weapon; import io.anuke.ucore.UCore;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.GameMode;
import io.anuke.mindustry.world.Map;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Settings;
import io.anuke.ucore.entities.Entities;
import java.io.*; import java.io.*;
import java.util.Arrays;
import java.util.Date;
import static io.anuke.mindustry.Vars.android;
/*
* Save format:
*
* --META--
*
* Save file version ID (int)
* Last saved timestamp (long)
*
* --STATE DATA--
* Wave (int)
* Wave countdown time (float)
*
* Gamemode Ordinal (byte)
* Map ordinal (byte)
*
* Player X (float)
* Player Y (float)
* Player health (int)
*
* Amount of weapons (byte)
* (weapon list)
* Weapon enum ordinal (byte)
*
* Amount of items (byte)
* (item list)
* Item ID (byte)
* Item amount (int)
*
* --ENEMY DATA--
* Amount of enemies (int)
* (enemy list)
* enemy type ID (byte)
* spawn lane (byte)
* x (float)
* y (float)
* tier (byte)
* health (int)
*
*
* --MAP DATA--
* Seed (int)
* Amount of tiles (int)
* (tile list)
* Tile position, as a single integer, in the format x+y*width
* Tile link - (byte)
* Tile type (boolean)- whether the block has a tile entity attached
* Block ID - the block ID (byte)
* (the following only applies to tile entity blocks)
* Block placerot (byte)
* Block health (int)
* Amount of items (byte)
* (item list)
* Item ID (byte)
* Item amount (int)
* Additional tile entity data (varies, check the TileEntity classes)
*/
public class SaveIO{ public class SaveIO{
/**Save file version ID. Should be incremented every breaking release.*/
private static final int fileVersionID = 12;
//TODO automatic registration of types? public static final OrderedMap<Integer, SaveFileVersion> versions = new OrderedMap(){{
public static final Array<Class<? extends Enemy>> enemyIDs = Array.with( put(12, new Save12());
Enemy.class, put(13, new Save13());
FastEnemy.class,
RapidEnemy.class,
FlamerEnemy.class,
TankEnemy.class,
BlastEnemy.class,
MortarEnemy.class,
TestEnemy.class,
HealerEnemy.class,
TitanEnemy.class,
EmpEnemy.class
);
public static final ObjectMap<Class<? extends Enemy>, Byte> idEnemies = new ObjectMap<Class<? extends Enemy>, Byte>(){{
for(int i = 0; i < enemyIDs.size; i ++){
put(enemyIDs.get(i), (byte)i);
}
}}; }};
public static void saveToSlot(int slot){ public static void saveToSlot(int slot){
@@ -146,6 +57,29 @@ public class SaveIO{
} }
} }
public static boolean checkConvert(int slot){
try{
DataInputStream stream = readSlotMeta(slot);
int version = stream.readInt();
stream.close();
if(version != getVersion().version){
UCore.log("Converting slot " + slot + ": " + version + " -> " + getVersion().version);
stream = readSlotMeta(slot);
SaveFileVersion target = versions.get(version);
target.read(stream);
stream.close();
saveToSlot(slot);
return true;
}
return false;
}catch (IOException e){
throw new RuntimeException(e);
}
}
public static boolean isSaveValid(FileHandle file){ public static boolean isSaveValid(FileHandle file){
return isSaveValid(new DataInputStream(file.read())); return isSaveValid(new DataInputStream(file.read()));
} }
@@ -154,7 +88,7 @@ public class SaveIO{
try{ try{
SaveMeta meta = getData(stream); SaveMeta meta = getData(stream);
return meta.version == fileVersionID && meta.map != null; return meta.map != null;
}catch (Exception e){ }catch (Exception e){
return false; return false;
} }
@@ -167,12 +101,9 @@ public class SaveIO{
public static SaveMeta getData(DataInputStream stream){ public static SaveMeta getData(DataInputStream stream){
try{ try{
int version = stream.readInt(); //read version SaveMeta meta = getVersion().getData(stream);
long time = stream.readLong(); //read last saved time stream.close();
byte mode = stream.readByte(); //read the gamemode return meta;
byte map = stream.readByte(); //read the map
int wave = stream.readInt(); //read the wave
return new SaveMeta(version, time, mode, map, wave);
}catch (IOException e){ }catch (IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -188,131 +119,12 @@ public class SaveIO{
public static void write(OutputStream os){ public static void write(OutputStream os){
try(DataOutputStream stream = new DataOutputStream(os)){ DataOutputStream stream;
//--META--
stream.writeInt(fileVersionID); //version id
stream.writeLong(TimeUtils.millis()); //last saved
//--GENERAL STATE--
stream.writeByte(Vars.control.getMode().ordinal()); //gamemode
stream.writeByte(Vars.world.getMap().id); //map ID
stream.writeInt(Vars.control.getWave()); //wave
stream.writeFloat(Vars.control.getWaveCountdown()); //wave countdown
stream.writeFloat(Vars.player.x); //player x/y
stream.writeFloat(Vars.player.y);
stream.writeInt(Vars.player.health); //player health
stream.writeByte(Vars.control.getWeapons().size - 1); //amount of weapons
//start at 1, because the first weapon is always the starter - ignore that
for(int i = 1; i < Vars.control.getWeapons().size; i ++){
stream.writeByte(Vars.control.getWeapons().get(i).ordinal()); //weapon ordinal
}
//--INVENTORY--
int l = Vars.control.getItems().length;
int itemsize = 0;
for(int i = 0; i < l; i ++){
if(Vars.control.getItems()[i] > 0){
itemsize ++;
}
}
stream.writeByte(itemsize); //amount of items
for(int i = 0; i < l; i ++){
if(Vars.control.getItems()[i] > 0){
stream.writeByte(i); //item ID
stream.writeInt(Vars.control.getItems()[i]); //item amount
}
}
//--ENEMIES--
int totalEnemies = 0;
Array<Enemy> enemies = Vars.control.enemyGroup.all();
for(int i = 0; i < enemies.size; i ++){
Enemy enemy = enemies.get(i);
if(idEnemies.containsKey(enemy.getClass())){
totalEnemies ++;
}
}
stream.writeInt(totalEnemies); //enemy amount
for(int i = 0; i < enemies.size; i ++){
Enemy enemy = enemies.get(i);
if(idEnemies.containsKey(enemy.getClass())){
stream.writeByte(idEnemies.get(enemy.getClass())); //type
stream.writeByte(enemy.lane); //lane
stream.writeFloat(enemy.x); //x
stream.writeFloat(enemy.y); //y
stream.writeByte(enemy.tier); //tier
stream.writeInt(enemy.health); //health
}
}
//--MAP DATA--
//seed
stream.writeInt(Vars.world.getSeed());
int totalblocks = 0;
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
totalblocks ++;
}
}
}
//tile amount
stream.writeInt(totalblocks);
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
stream.writeInt(x + y*Vars.world.width()); //tile pos
stream.writeByte(tile.link);
stream.writeBoolean(tile.entity != null); //whether it has a tile entity
stream.writeInt(tile.block().id); //block ID
if(tile.entity != null){
stream.writeByte(tile.getRotation()); //placerot
stream.writeInt(tile.entity.health); //health
int amount = 0;
for(int i = 0; i < tile.entity.items.length; i ++){
if(tile.entity.items[i] > 0) amount ++;
}
stream.writeByte(amount); //amount of items
for(int i = 0; i < tile.entity.items.length; i ++){
if(tile.entity.items[i] > 0){
stream.writeByte(i); //item ID
stream.writeInt(tile.entity.items[i]); //item amount
}
}
tile.entity.write(stream);
}
}
}
}
try{
stream = new DataOutputStream(os);
getVersion().write(stream);
stream.close();
}catch (IOException e){ }catch (IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -325,149 +137,18 @@ public class SaveIO{
//TODO GWT support //TODO GWT support
public static void load(InputStream is){ public static void load(InputStream is){
try(DataInputStream stream = new DataInputStream(is)){ DataInputStream stream;
int version = stream.readInt();
/*long loadTime = */stream.readLong();
if(version != fileVersionID){
throw new RuntimeException("Save file version mismatch!");
}
//general state
byte mode = stream.readByte();
byte mapid = stream.readByte();
int wave = stream.readInt();
float wavetime = stream.readFloat();
float playerx = stream.readFloat();
float playery = stream.readFloat();
int playerhealth = stream.readInt();
Vars.player.x = playerx;
Vars.player.y = playery;
Vars.player.health = playerhealth;
Vars.control.setMode(GameMode.values()[mode]);
Core.camera.position.set(playerx, playery, 0);
//weapons
Vars.control.getWeapons().clear();
Vars.control.getWeapons().add(Weapon.blaster);
Vars.player.weapon = Weapon.blaster;
int weapons = stream.readByte();
for(int i = 0; i < weapons; i ++){
Vars.control.addWeapon(Weapon.values()[stream.readByte()]);
}
Vars.ui.updateWeapons();
//inventory
int totalItems = stream.readByte();
Arrays.fill(Vars.control.getItems(), 0);
for(int i = 0; i < totalItems; i ++){
Item item = Item.getByID(stream.readByte());
int amount = stream.readInt();
Vars.control.getItems()[item.id] = amount;
}
Vars.ui.updateItems();
//enemies
Entities.clear();
int enemies = stream.readInt();
Array<Enemy> enemiesToUpdate = new Array<>();
for(int i = 0; i < enemies; i ++){
byte type = stream.readByte();
int lane = stream.readByte();
float x = stream.readFloat();
float y = stream.readFloat();
byte tier = stream.readByte();
int health = stream.readInt();
try{
Enemy enemy = ClassReflection.newInstance(enemyIDs.get(type));
enemy.lane = lane;
enemy.health = health;
enemy.x = x;
enemy.y = y;
enemy.tier = tier;
enemy.add(Vars.control.enemyGroup);
enemiesToUpdate.add(enemy);
}catch (Exception e){
throw new RuntimeException(e);
}
}
Vars.control.setWaveData(enemies, wave, wavetime);
if(!android)
Vars.player.add();
//map
int seed = stream.readInt();
int tiles = stream.readInt();
Vars.world.loadMap(Vars.world.maps().getMap(mapid), seed);
Vars.renderer.clearTiles();
for(Enemy enemy : enemiesToUpdate){
enemy.node = -2;
}
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
//remove breakables like rocks
if(tile.breakable()){
Vars.world.tile(x, y).setBlock(Blocks.air);
}
}
}
for(int i = 0; i < tiles; i ++){
int pos = stream.readInt();
byte link = stream.readByte();
boolean hasEntity = stream.readBoolean();
int blockid = stream.readInt();
Tile tile = Vars.world.tile(pos % Vars.world.width(), pos / Vars.world.width());
tile.setBlock(Block.getByID(blockid));
tile.link = link;
if(hasEntity){
byte rotation = stream.readByte();
int health = stream.readInt();
int items = stream.readByte();
tile.entity.health = health;
tile.setRotation(rotation);
for(int j = 0; j < items; j ++){
int itemid = stream.readByte();
int itemamount = stream.readInt();
tile.entity.items[itemid] = itemamount;
}
tile.entity.read(stream);
}
}
try{
stream = new DataInputStream(is);
getVersion().read(stream);
stream.close();
}catch (IOException e){ }catch (IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static SaveFileVersion getVersion(){
return versions.get(versions.orderedKeys().peek());
}
} }

View File

@@ -34,6 +34,12 @@ public class Saves {
} }
} }
public void convertSaves(){
for(SaveSlot slot : saves){
SaveIO.checkConvert(slot.index);
}
}
public SaveSlot getCurrent() { public SaveSlot getCurrent() {
return current; return current;
} }

View File

@@ -0,0 +1,300 @@
package io.anuke.mindustry.io.versions;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.io.SaveFileVersion;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.GameMode;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.Entities;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import static io.anuke.mindustry.Vars.android;
public class Save12 extends SaveFileVersion {
public Save12(){
super(12);
}
@Override
public void read(DataInputStream stream) throws IOException {
int version = stream.readInt();
/*long loadTime = */stream.readLong();
if(version != this.version){
throw new RuntimeException("Save file version mismatch!");
}
//general state
byte mode = stream.readByte();
byte mapid = stream.readByte();
int wave = stream.readInt();
float wavetime = stream.readFloat();
float playerx = stream.readFloat();
float playery = stream.readFloat();
int playerhealth = stream.readInt();
Vars.player.x = playerx;
Vars.player.y = playery;
Vars.player.health = playerhealth;
Vars.control.setMode(GameMode.values()[mode]);
Core.camera.position.set(playerx, playery, 0);
//weapons
Vars.control.getWeapons().clear();
Vars.control.getWeapons().add(Weapon.blaster);
Vars.player.weapon = Weapon.blaster;
int weapons = stream.readByte();
for(int i = 0; i < weapons; i ++){
Vars.control.addWeapon(Weapon.values()[stream.readByte()]);
}
Vars.ui.updateWeapons();
//inventory
int totalItems = stream.readByte();
Arrays.fill(Vars.control.getItems(), 0);
for(int i = 0; i < totalItems; i ++){
Item item = Item.getByID(stream.readByte());
int amount = stream.readInt();
Vars.control.getItems()[item.id] = amount;
}
Vars.ui.updateItems();
//enemies
Entities.clear();
int enemies = stream.readInt();
Array<Enemy> enemiesToUpdate = new Array<>();
for(int i = 0; i < enemies; i ++){
byte type = stream.readByte();
int lane = stream.readByte();
float x = stream.readFloat();
float y = stream.readFloat();
byte tier = stream.readByte();
int health = stream.readInt();
try{
Enemy enemy = ClassReflection.newInstance(enemyIDs.get(type));
enemy.lane = lane;
enemy.health = health;
enemy.x = x;
enemy.y = y;
enemy.tier = tier;
enemy.add(Vars.control.enemyGroup);
enemiesToUpdate.add(enemy);
}catch (Exception e){
throw new RuntimeException(e);
}
}
Vars.control.setWaveData(enemies, wave, wavetime);
if(!android)
Vars.player.add();
//map
int seed = stream.readInt();
int tiles = stream.readInt();
Vars.world.loadMap(Vars.world.maps().getMap(mapid), seed);
Vars.renderer.clearTiles();
for(Enemy enemy : enemiesToUpdate){
enemy.node = -2;
}
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
//remove breakables like rocks
if(tile.breakable()){
Vars.world.tile(x, y).setBlock(Blocks.air);
}
}
}
for(int i = 0; i < tiles; i ++){
int pos = stream.readInt();
byte link = stream.readByte();
boolean hasEntity = stream.readBoolean();
int blockid = stream.readInt();
Tile tile = Vars.world.tile(pos % Vars.world.width(), pos / Vars.world.width());
tile.setBlock(Block.getByID(blockid));
tile.link = link;
if(hasEntity){
byte rotation = stream.readByte();
int health = stream.readInt();
int items = stream.readByte();
tile.entity.health = health;
tile.setRotation(rotation);
for(int j = 0; j < items; j ++){
int itemid = stream.readByte();
int itemamount = stream.readInt();
tile.entity.items[itemid] = itemamount;
}
tile.entity.read(stream);
}
}
}
@Override
public void write(DataOutputStream stream) throws IOException {
//--META--
stream.writeInt(version); //version id
stream.writeLong(TimeUtils.millis()); //last saved
//--GENERAL STATE--
stream.writeByte(Vars.control.getMode().ordinal()); //gamemode
stream.writeByte(Vars.world.getMap().id); //map ID
stream.writeInt(Vars.control.getWave()); //wave
stream.writeFloat(Vars.control.getWaveCountdown()); //wave countdown
stream.writeFloat(Vars.player.x); //player x/y
stream.writeFloat(Vars.player.y);
stream.writeInt(Vars.player.health); //player health
stream.writeByte(Vars.control.getWeapons().size - 1); //amount of weapons
//start at 1, because the first weapon is always the starter - ignore that
for(int i = 1; i < Vars.control.getWeapons().size; i ++){
stream.writeByte(Vars.control.getWeapons().get(i).ordinal()); //weapon ordinal
}
//--INVENTORY--
int l = Vars.control.getItems().length;
int itemsize = 0;
for(int i = 0; i < l; i ++){
if(Vars.control.getItems()[i] > 0){
itemsize ++;
}
}
stream.writeByte(itemsize); //amount of items
for(int i = 0; i < l; i ++){
if(Vars.control.getItems()[i] > 0){
stream.writeByte(i); //item ID
stream.writeInt(Vars.control.getItems()[i]); //item amount
}
}
//--ENEMIES--
int totalEnemies = 0;
Array<Enemy> enemies = Vars.control.enemyGroup.all();
for(int i = 0; i < enemies.size; i ++){
Enemy enemy = enemies.get(i);
if(idEnemies.containsKey(enemy.getClass())){
totalEnemies ++;
}
}
stream.writeInt(totalEnemies); //enemy amount
for(int i = 0; i < enemies.size; i ++){
Enemy enemy = enemies.get(i);
if(idEnemies.containsKey(enemy.getClass())){
stream.writeByte(idEnemies.get(enemy.getClass())); //type
stream.writeByte(enemy.lane); //lane
stream.writeFloat(enemy.x); //x
stream.writeFloat(enemy.y); //y
stream.writeByte(enemy.tier); //tier
stream.writeInt(enemy.health); //health
}
}
//--MAP DATA--
//seed
stream.writeInt(Vars.world.getSeed());
int totalblocks = 0;
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
totalblocks ++;
}
}
}
//tile amount
stream.writeInt(totalblocks);
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
stream.writeInt(x + y*Vars.world.width()); //tile pos
stream.writeByte(tile.link);
stream.writeBoolean(tile.entity != null); //whether it has a tile entity
stream.writeInt(tile.block().id); //block ID
if(tile.entity != null){
stream.writeByte(tile.getRotation()); //placerot
stream.writeInt(tile.entity.health); //health
int amount = 0;
for(int i = 0; i < tile.entity.items.length; i ++){
if(tile.entity.items[i] > 0) amount ++;
}
stream.writeByte(amount); //amount of items
for(int i = 0; i < tile.entity.items.length; i ++){
if(tile.entity.items[i] > 0){
stream.writeByte(i); //item ID
stream.writeInt(tile.entity.items[i]); //item amount
}
}
tile.entity.write(stream);
}
}
}
}
}
}

View File

@@ -0,0 +1,333 @@
package io.anuke.mindustry.io.versions;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.io.SaveFileVersion;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.GameMode;
import io.anuke.mindustry.world.Generator;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.types.BlockPart;
import io.anuke.mindustry.world.blocks.types.Rock;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.Entities;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import static io.anuke.mindustry.Vars.android;
public class Save13 extends SaveFileVersion {
public Save13(){
super(13);
}
@Override
public void read(DataInputStream stream) throws IOException {
int version = stream.readInt();
/*long loadTime = */stream.readLong();
if(version != this.version){
throw new RuntimeException("Save file version mismatch!");
}
//general state
byte mode = stream.readByte();
byte mapid = stream.readByte();
int wave = stream.readInt();
float wavetime = stream.readFloat();
float playerx = stream.readFloat();
float playery = stream.readFloat();
int playerhealth = stream.readInt();
Vars.player.x = playerx;
Vars.player.y = playery;
Vars.player.health = playerhealth;
Vars.control.setMode(GameMode.values()[mode]);
Core.camera.position.set(playerx, playery, 0);
//weapons
Vars.control.getWeapons().clear();
Vars.control.getWeapons().add(Weapon.blaster);
Vars.player.weapon = Weapon.blaster;
int weapons = stream.readByte();
for(int i = 0; i < weapons; i ++){
Vars.control.addWeapon(Weapon.values()[stream.readByte()]);
}
Vars.ui.updateWeapons();
//inventory
int totalItems = stream.readByte();
Arrays.fill(Vars.control.getItems(), 0);
for(int i = 0; i < totalItems; i ++){
Item item = Item.getByID(stream.readByte());
int amount = stream.readInt();
Vars.control.getItems()[item.id] = amount;
}
Vars.ui.updateItems();
//enemies
Entities.clear();
int enemies = stream.readInt();
Array<Enemy> enemiesToUpdate = new Array<>();
for(int i = 0; i < enemies; i ++){
byte type = stream.readByte();
int lane = stream.readByte();
float x = stream.readFloat();
float y = stream.readFloat();
byte tier = stream.readByte();
int health = stream.readShort();
try{
Enemy enemy = ClassReflection.newInstance(enemyIDs.get(type));
enemy.lane = lane;
enemy.health = health;
enemy.x = x;
enemy.y = y;
enemy.tier = tier;
enemy.add(Vars.control.enemyGroup);
enemiesToUpdate.add(enemy);
}catch (Exception e){
throw new RuntimeException(e);
}
}
Vars.control.setWaveData(enemies, wave, wavetime);
if(!android)
Vars.player.add();
//map
int seed = stream.readInt();
Vars.world.loadMap(Vars.world.maps().getMap(mapid), seed);
Vars.renderer.clearTiles();
for(Enemy enemy : enemiesToUpdate){
enemy.node = -2;
}
int rocks = stream.readInt();
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
//remove breakables like rocks
if(tile.breakable()){
Vars.world.tile(x, y).setBlock(Blocks.air);
}
}
}
for(int i = 0; i < rocks; i ++){
int pos = stream.readInt();
Tile tile = Vars.world.tile(pos % Vars.world.width(), pos / Vars.world.width());
Block result = Generator.rocks.get(tile.floor());
if(result != null) tile.setBlock(result);
}
int tiles = stream.readInt();
for(int i = 0; i < tiles; i ++){
int pos = stream.readInt();
int blockid = stream.readInt();
Tile tile = Vars.world.tile(pos % Vars.world.width(), pos / Vars.world.width());
tile.setBlock(Block.getByID(blockid));
if(blockid == Blocks.blockpart.id){
tile.link = stream.readByte();
}
if(tile.entity != null){
byte rotation = stream.readByte();
short health = stream.readShort();
int items = stream.readByte();
tile.entity.health = health;
tile.setRotation(rotation);
for(int j = 0; j < items; j ++){
int itemid = stream.readByte();
int itemamount = stream.readInt();
tile.entity.items[itemid] = itemamount;
}
tile.entity.read(stream);
}
}
}
@Override
public void write(DataOutputStream stream) throws IOException {
//--META--
stream.writeInt(version); //version id
stream.writeLong(TimeUtils.millis()); //last saved
//--GENERAL STATE--
stream.writeByte(Vars.control.getMode().ordinal()); //gamemode
stream.writeByte(Vars.world.getMap().id); //map ID
stream.writeInt(Vars.control.getWave()); //wave
stream.writeFloat(Vars.control.getWaveCountdown()); //wave countdown
stream.writeFloat(Vars.player.x); //player x/y
stream.writeFloat(Vars.player.y);
stream.writeInt(Vars.player.health); //player health
stream.writeByte(Vars.control.getWeapons().size - 1); //amount of weapons
//start at 1, because the first weapon is always the starter - ignore that
for(int i = 1; i < Vars.control.getWeapons().size; i ++){
stream.writeByte(Vars.control.getWeapons().get(i).ordinal()); //weapon ordinal
}
//--INVENTORY--
int l = Vars.control.getItems().length;
int itemsize = 0;
for(int i = 0; i < l; i ++){
if(Vars.control.getItems()[i] > 0){
itemsize ++;
}
}
stream.writeByte(itemsize); //amount of items
for(int i = 0; i < l; i ++){
if(Vars.control.getItems()[i] > 0){
stream.writeByte(i); //item ID
stream.writeInt(Vars.control.getItems()[i]); //item amount
}
}
//--ENEMIES--
int totalEnemies = 0;
Array<Enemy> enemies = Vars.control.enemyGroup.all();
for(int i = 0; i < enemies.size; i ++){
Enemy enemy = enemies.get(i);
if(idEnemies.containsKey(enemy.getClass())){
totalEnemies ++;
}
}
stream.writeInt(totalEnemies); //enemy amount
for(int i = 0; i < enemies.size; i ++){
Enemy enemy = enemies.get(i);
if(idEnemies.containsKey(enemy.getClass())){
stream.writeByte(idEnemies.get(enemy.getClass())); //type
stream.writeByte(enemy.lane); //lane
stream.writeFloat(enemy.x); //x
stream.writeFloat(enemy.y); //y
stream.writeByte(enemy.tier); //tier
stream.writeShort(enemy.health); //health
}
}
//--MAP DATA--
//seed
stream.writeInt(Vars.world.getSeed());
int totalblocks = 0;
int totalrocks = 0;
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
if(tile.block() instanceof Rock){
totalrocks ++;
}else{
totalblocks ++;
}
}
}
}
//amount of rocks
stream.writeInt(totalrocks);
//write all rocks
for(int x = 0; x < Vars.world.width(); x ++) {
for (int y = 0; y < Vars.world.height(); y++) {
Tile tile = Vars.world.tile(x, y);
if (tile.block() instanceof Rock) {
stream.writeInt(tile.packedPosition());
}
}
}
//write all blocks
stream.writeInt(totalblocks);
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable() && !(tile.block() instanceof Rock)){
stream.writeInt(x + y*Vars.world.width()); //tile pos
stream.writeInt(tile.block().id); //block ID
if(tile.block() instanceof BlockPart) stream.writeByte(tile.link);
if(tile.entity != null){
stream.writeByte(tile.getRotation()); //placerot
stream.writeShort(tile.entity.health); //health
byte amount = 0;
for(int i = 0; i < tile.entity.items.length; i ++){
if(tile.entity.items[i] > 0) amount ++;
}
stream.writeByte(amount); //amount of items
for(int i = 0; i < tile.entity.items.length; i ++){
if(tile.entity.items[i] > 0){
stream.writeByte(i); //item ID
stream.writeInt(tile.entity.items[i]); //item amount
}
}
tile.entity.write(stream);
}
}
}
}
}
}

View File

@@ -7,18 +7,18 @@ import io.anuke.mindustry.world.blocks.*;
import static io.anuke.mindustry.resource.Section.*; import static io.anuke.mindustry.resource.Section.*;
public enum Recipe{ public enum Recipe{
stonewall(defense, DefenseBlocks.stonewall, stack(Item.stone, 2)), stonewall(defense, DefenseBlocks.stonewall, stack(Item.stone, 12)),
ironwall(defense, DefenseBlocks.ironwall, stack(Item.iron, 2)), ironwall(defense, DefenseBlocks.ironwall, stack(Item.iron, 12)),
steelwall(defense, DefenseBlocks.steelwall, stack(Item.steel, 2)), steelwall(defense, DefenseBlocks.steelwall, stack(Item.steel, 11)),
titaniumwall(defense, DefenseBlocks.titaniumwall, stack(Item.titanium, 2)), titaniumwall(defense, DefenseBlocks.titaniumwall, stack(Item.titanium, 12)),
duriumwall(defense, DefenseBlocks.diriumwall, stack(Item.dirium, 2)), duriumwall(defense, DefenseBlocks.diriumwall, stack(Item.dirium, 12)),
//compositewall(defense, DefenseBlocks.compositewall, stack(Item.dirium, 2), stack(Item.titanium, 2), stack(Item.steel, 2), stack(Item.iron, 2)), //compositewall(defense, DefenseBlocks.compositewall, stack(Item.dirium, 2), stack(Item.titanium, 2), stack(Item.steel, 2), stack(Item.iron, 2)),
steelwalllarge(defense, DefenseBlocks.steelwalllarge, stack(Item.steel, 8)), steelwalllarge(defense, DefenseBlocks.steelwalllarge, stack(Item.steel, 12*4)),
titaniumwalllarge(defense, DefenseBlocks.titaniumwalllarge, stack(Item.titanium, 8)), titaniumwalllarge(defense, DefenseBlocks.titaniumwalllarge, stack(Item.titanium, 12*4)),
duriumwalllarge(defense, DefenseBlocks.diriumwalllarge, stack(Item.dirium, 8)), duriumwalllarge(defense, DefenseBlocks.diriumwalllarge, stack(Item.dirium, 12*4)),
door(defense, DefenseBlocks.door, stack(Item.steel, 3), stack(Item.iron, 3)), door(defense, DefenseBlocks.door, stack(Item.steel, 3), stack(Item.iron, 3*4)),
largedoor(defense, DefenseBlocks.largedoor, stack(Item.steel, 3*4), stack(Item.iron, 3*4)), largedoor(defense, DefenseBlocks.largedoor, stack(Item.steel, 3*4), stack(Item.iron, 3*4*4)),
titaniumshieldwall(defense, DefenseBlocks.titaniumshieldwall, stack(Item.titanium, 3)), titaniumshieldwall(defense, DefenseBlocks.titaniumshieldwall, stack(Item.titanium, 16)),
conveyor(distribution, DistributionBlocks.conveyor, stack(Item.stone, 1)), conveyor(distribution, DistributionBlocks.conveyor, stack(Item.stone, 1)),
steelconveyor(distribution, DistributionBlocks.steelconveyor, stack(Item.steel, 1)), steelconveyor(distribution, DistributionBlocks.steelconveyor, stack(Item.steel, 1)),

View File

@@ -74,11 +74,9 @@ public class MenuFragment implements Fragment{
new imagebutton("icon-add", isize, () -> ui.showJoinGame()).text("$text.joingame").padTop(4f); new imagebutton("icon-add", isize, () -> ui.showJoinGame()).text("$text.joingame").padTop(4f);
if(Mindustry.donationsCallable != null){ new imagebutton("icon-donate", isize, () -> {
new imagebutton("icon-donate", isize, () -> { Mindustry.platforms.openDonations();
Mindustry.donationsCallable.run(); }).text("$text.donate").padTop(4f);
}).text("$text.donate").padTop(4f);
}
visible(()->GameState.is(State.menu)); visible(()->GameState.is(State.menu));
}}.end(); }}.end();

View File

@@ -81,16 +81,15 @@ public class Block{
public Layer layer2 = null; public Layer layer2 = null;
public Block(String name) { public Block(String name) {
blocks.add(this);
this.name = name; this.name = name;
this.formalName = Bundles.get("block." + name + ".name", name); this.formalName = Bundles.get("block." + name + ".name", name);
this.description = Bundles.getOrNull("block." + name + ".description"); this.description = Bundles.getOrNull("block." + name + ".description");
this.fullDescription = Bundles.getOrNull("block." + name + ".fulldescription"); this.fullDescription = Bundles.getOrNull("block." + name + ".fulldescription");
this.solid = false; this.solid = false;
this.id = lastid++; this.id = lastid++;
}
blocks.add(this);
}
public boolean isLayer(Tile tile){return true;} public boolean isLayer(Tile tile){return true;}
public boolean isLayer2(Tile tile){return true;} public boolean isLayer2(Tile tile){return true;}

View File

@@ -0,0 +1,19 @@
package io.anuke.mindustry.world;
import io.anuke.mindustry.world.blocks.*;
public class BlockLoader {
public static void load(){
Block[] blockClasses = {
Blocks.air,
DefenseBlocks.compositewall,
DistributionBlocks.conduit,
ProductionBlocks.coaldrill,
WeaponBlocks.chainturret,
SpecialBlocks.enemySpawn
//add any new block sections here
};
}
}

View File

@@ -22,7 +22,9 @@ public class Blocks{
public void draw(Tile tile){} public void draw(Tile tile){}
}, },
blockpart = new BlockPart(), blockpart = new BlockPart(){
},
deepwater = new Floor("deepwater"){{ deepwater = new Floor("deepwater"){{
variants = 0; variants = 0;
@@ -99,15 +101,15 @@ public class Blocks{
drops = new ItemStack(Item.uranium, 1); drops = new ItemStack(Item.uranium, 1);
}}, }},
dirt = new Floor("dirt"), dirt = new Floor("dirt"){},
sand = new Floor("sand"), sand = new Floor("sand"){},
ice = new Floor("ice"), ice = new Floor("ice"){},
snow = new Floor("snow"), snow = new Floor("snow"){},
grass = new Floor("grass"), grass = new Floor("grass"){},
sandblock = new StaticBlock("sandblock"){{ sandblock = new StaticBlock("sandblock"){{
solid = true; solid = true;

View File

@@ -6,44 +6,45 @@ import io.anuke.mindustry.world.blocks.types.Wall;
import io.anuke.mindustry.world.blocks.types.defense.*; import io.anuke.mindustry.world.blocks.types.defense.*;
public class DefenseBlocks{ public class DefenseBlocks{
static final int wallHealthMultiplier = 4;
public static final Block public static final Block
stonewall = new Wall("stonewall"){{ stonewall = new Wall("stonewall"){{
health = 50; health = 50*wallHealthMultiplier;
}}, }},
ironwall = new Wall("ironwall"){{ ironwall = new Wall("ironwall"){{
health = 80; health = 80*wallHealthMultiplier;
}}, }},
steelwall = new Wall("steelwall"){{ steelwall = new Wall("steelwall"){{
health = 110; health = 110*wallHealthMultiplier;
}}, }},
titaniumwall = new Wall("titaniumwall"){{ titaniumwall = new Wall("titaniumwall"){{
health = 150; health = 150*wallHealthMultiplier;
}}, }},
diriumwall = new Wall("duriumwall"){{ diriumwall = new Wall("duriumwall"){{
health = 190; health = 190*wallHealthMultiplier;
}}, }},
compositewall = new Wall("compositewall"){{ compositewall = new Wall("compositewall"){{
health = 270; health = 270*wallHealthMultiplier;
}}, }},
steelwalllarge = new Wall("steelwall-large"){{ steelwalllarge = new Wall("steelwall-large"){{
health = 110*4; health = 110*4*wallHealthMultiplier;
width = height = 2; width = height = 2;
}}, }},
titaniumwalllarge = new Wall("titaniumwall-large"){{ titaniumwalllarge = new Wall("titaniumwall-large"){{
health = 150*4; health = 150*4*wallHealthMultiplier;
width = height = 2; width = height = 2;
}}, }},
diriumwalllarge = new Wall("duriumwall-large"){{ diriumwalllarge = new Wall("duriumwall-large"){{
health = 190*4; health = 190*4*wallHealthMultiplier;
width = height = 2; width = height = 2;
}}, }},
titaniumshieldwall = new ShieldedWallBlock("titaniumshieldwall"){{ titaniumshieldwall = new ShieldedWallBlock("titaniumshieldwall"){{
health = 150; health = 150*wallHealthMultiplier;
}}, }},
repairturret = new RepairTurret("repairturret"){ repairturret = new RepairTurret("repairturret"){
@@ -65,16 +66,16 @@ public class DefenseBlocks{
shieldgenerator = new ShieldBlock("shieldgenerator"){ shieldgenerator = new ShieldBlock("shieldgenerator"){
{ {
health = 100*wallHealthMultiplier;
} }
}, },
door = new Door("door"){{ door = new Door("door"){{
health = 90; health = 90*wallHealthMultiplier;
}}, }},
largedoor = new Door("door-large"){{ largedoor = new Door("door-large"){{
openfx = Fx.dooropenlarge; openfx = Fx.dooropenlarge;
closefx = Fx.doorcloselarge; closefx = Fx.doorcloselarge;
health = 90*4; health = 90*4*wallHealthMultiplier;
width = height = 2; width = height = 2;
}}; }};
} }

View File

@@ -1,6 +1,5 @@
package io.anuke.mindustry.world.blocks; package io.anuke.mindustry.world.blocks;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.graphics.Fx; import io.anuke.mindustry.graphics.Fx;
import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.resource.Item;
@@ -14,14 +13,15 @@ import io.anuke.ucore.core.Effects;
public class ProductionBlocks{ public class ProductionBlocks{
public static final Block public static final Block
core = new CoreBlock("core"), core = new CoreBlock("core"){},
pump = new Pump("pump"){{ pump = new Pump("pump"){},
}},
fluxpump = new Pump("fluxpump"){{ fluxpump = new Pump("fluxpump"){
pumpAmount = 3f; {
}}, pumpAmount = 3f;
}
},
smelter = new Crafter("smelter"){ smelter = new Crafter("smelter"){
{ {
@@ -64,19 +64,6 @@ public class ProductionBlocks{
} }
}, },
//TODO
/*siliconextractor = new LiquidCrafter("siliconextractor"){
{
input = Item.sand;
inputAmount = 5;
inputLiquid = Liquid.water;
liquidAmount = 18.99f;
output = Item.silicon;
health = 50;
purifyTime = 50;
}
},*/
oilrefinery = new LiquidCrafter("oilrefinery"){ oilrefinery = new LiquidCrafter("oilrefinery"){
{ {
inputLiquid = Liquid.oil; inputLiquid = Liquid.oil;
@@ -116,32 +103,42 @@ public class ProductionBlocks{
} }
}, },
stonedrill = new Drill("stonedrill"){{ stonedrill = new Drill("stonedrill"){
resource = Blocks.stone; {
result = Item.stone; resource = Blocks.stone;
time = 4; result = Item.stone;
}}, time = 4;
}
},
irondrill = new Drill("irondrill"){{ irondrill = new Drill("irondrill"){
resource = Blocks.iron; {
result = Item.iron; resource = Blocks.iron;
}}, result = Item.iron;
}
},
coaldrill = new Drill("coaldrill"){{ coaldrill = new Drill("coaldrill"){
resource = Blocks.coal; {
result = Item.coal; resource = Blocks.coal;
}}, result = Item.coal;
}
},
uraniumdrill = new Drill("uraniumdrill"){{ uraniumdrill = new Drill("uraniumdrill"){
resource = Blocks.uranium; {
result = Item.uranium; resource = Blocks.uranium;
time = 7; result = Item.uranium;
}}, time = 7;
}
},
titaniumdrill = new Drill("titaniumdrill"){{ titaniumdrill = new Drill("titaniumdrill"){
resource = Blocks.titanium; {
result = Item.titanium; resource = Blocks.titanium;
}}, result = Item.titanium;
}
},
omnidrill = new Drill("omnidrill"){ omnidrill = new Drill("omnidrill"){
{ {
@@ -210,4 +207,16 @@ public class ProductionBlocks{
breaktime *= 2.3f; breaktime *= 2.3f;
} }
}; };
/*
siliconextractor = new LiquidCrafter("siliconextractor"){
{
input = Item.sand;
inputAmount = 5;
inputLiquid = Liquid.water;
liquidAmount = 18.99f;
output = Item.sand;
health = 50;
purifyTime = 50;
}
}*/;
} }

View File

@@ -4,6 +4,6 @@ import io.anuke.mindustry.world.Block;
public class SpecialBlocks{ public class SpecialBlocks{
public static final Block public static final Block
playerSpawn = new Block("playerspawn"), playerSpawn = new Block("playerspawn"){},
enemySpawn = new Block("enemyspawn"); enemySpawn = new Block("enemyspawn"){};
} }

View File

@@ -17,15 +17,14 @@ import io.anuke.ucore.util.Strings;
public class ShieldBlock extends PowerBlock{ public class ShieldBlock extends PowerBlock{
public float shieldRadius = 40f; public float shieldRadius = 40f;
public float powerDrain = 0.005f; public float powerDrain = 0.005f;
public float powerPerDamage = 0.13f; public float powerPerDamage = 0.1f;
public float maxRadius = 40f; public float maxRadius = 40f;
public float radiusScale = 200f; public float radiusScale = 240f;
public ShieldBlock(String name) { public ShieldBlock(String name) {
super(name); super(name);
voltage = powerDrain; voltage = powerDrain;
powerCapacity = 40f; powerCapacity = 40f;
health = 100;
} }
@Override @Override

View File

@@ -1,19 +1,19 @@
package io.anuke.mindustry.world.blocks.types.defense; package io.anuke.mindustry.world.blocks.types.defense;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.PowerBlock; import io.anuke.mindustry.world.blocks.types.PowerBlock;
import io.anuke.ucore.core.Draw; import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.util.Strings;
public class ShieldedWallBlock extends PowerBlock{ public class ShieldedWallBlock extends PowerBlock{
static final float hitTime = 18f; static final float hitTime = 18f;
static final Color hitColor = Color.SKY.cpy().mul(1.2f); static final Color hitColor = Color.SKY.cpy().mul(1.2f);
public float powerToDamage = 0.1f; public float powerPerDamage = 0.08f;
public ShieldedWallBlock(String name) { public ShieldedWallBlock(String name) {
super(name); super(name);
@@ -24,7 +24,7 @@ public class ShieldedWallBlock extends PowerBlock{
@Override @Override
public int handleDamage(Tile tile, int amount){ public int handleDamage(Tile tile, int amount){
float drain = amount * powerToDamage; float drain = amount * powerPerDamage;
ShieldedWallEntity entity = tile.entity(); ShieldedWallEntity entity = tile.entity();
if(entity.power > drain){ if(entity.power > drain){
@@ -32,7 +32,7 @@ public class ShieldedWallBlock extends PowerBlock{
entity.hit = hitTime; entity.hit = hitTime;
return 0; return 0;
}else if(entity.power > 0){ }else if(entity.power > 0){
int reduction = (int)(entity.power / powerToDamage); int reduction = (int)(entity.power / powerPerDamage);
entity.power = 0; entity.power = 0;
return amount - reduction; return amount - reduction;
@@ -41,13 +41,19 @@ public class ShieldedWallBlock extends PowerBlock{
return amount; return amount;
} }
@Override
public void getStats(Array<String> list){
super.getStats(list);
list.add("[powerinfo]Power Drain/damage: " + Strings.toFixed(powerPerDamage, 2));
}
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
super.draw(tile); super.draw(tile);
ShieldedWallEntity entity = tile.entity(); ShieldedWallEntity entity = tile.entity();
if(entity.power > powerToDamage){ if(entity.power > powerPerDamage){
Vars.renderer.addShield(() -> Draw.rect("blank", tile.worldx(), tile.worldy(), Vars.tilesize, Vars.tilesize)); Vars.renderer.addShield(() -> Draw.rect("blank", tile.worldx(), tile.worldy(), Vars.tilesize, Vars.tilesize));
} }

View File

@@ -61,31 +61,32 @@ public class DesktopLauncher {
} }
@Override @Override
public void addDialog(TextField field){ public void addDialog(TextField field){}
} @Override
public void openDonations(){}
@Override @Override
public void onSceneChange(String state, String details, String icon) { public void onSceneChange(String state, String details, String icon) {
DiscordRPC lib = DiscordRPC.INSTANCE; DiscordRPC lib = DiscordRPC.INSTANCE;
String applicationId = "397335883319083018"; String applicationId = "397335883319083018";
DiscordEventHandlers handlers = new DiscordEventHandlers(); DiscordEventHandlers handlers = new DiscordEventHandlers();
lib.Discord_Initialize(applicationId, handlers, true, ""); lib.Discord_Initialize(applicationId, handlers, true, "");
DiscordRichPresence presence = new DiscordRichPresence(); DiscordRichPresence presence = new DiscordRichPresence();
presence.startTimestamp = System.currentTimeMillis() / 1000; // epoch second presence.startTimestamp = System.currentTimeMillis() / 1000; // epoch second
presence.state = state; presence.state = state;
//presence.details = details; //presence.details = details;
presence.largeImageKey = "logo"; presence.largeImageKey = "logo";
presence.largeImageText = details; presence.largeImageText = details;
lib.Discord_UpdatePresence(presence); lib.Discord_UpdatePresence(presence);
} }
@Override @Override
public void onGameExit() { public void onGameExit() {
DiscordRPC.INSTANCE.Discord_Shutdown(); DiscordRPC.INSTANCE.Discord_Shutdown();
} }
}; };

View File

@@ -1,24 +1,26 @@
package io.anuke.mindustry.client; package io.anuke.mindustry.client;
import java.util.Date;
import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.backends.gwt.GwtApplication; import com.badlogic.gdx.backends.gwt.GwtApplication;
import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration; import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration;
import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderCallback; import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderCallback;
import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderState; import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderState;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.*; import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.i18n.shared.DateTimeFormat; import com.google.gwt.i18n.shared.DateTimeFormat;
import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.*; import com.google.gwt.user.client.ui.*;
import io.anuke.mindustry.Mindustry; import io.anuke.mindustry.Mindustry;
import io.anuke.mindustry.io.PlatformFunction; import io.anuke.mindustry.io.PlatformFunction;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
import java.util.Date;
public class HtmlLauncher extends GwtApplication { public class HtmlLauncher extends GwtApplication {
static final int WIDTH = 800; static final int WIDTH = 800;
static final int HEIGHT = 600; static final int HEIGHT = 600;
@@ -109,19 +111,16 @@ public class HtmlLauncher extends GwtApplication {
} }
@Override @Override
public void addDialog(TextField field){ public void addDialog(TextField field){}
}
@Override @Override
public void onSceneChange(String state, String details, String icon) { public void onSceneChange(String state, String details, String icon) {}
}
@Override @Override
public void onGameExit() { public void onGameExit() {}
} @Override
public void openDonations() {}
}; };
return new Mindustry(); return new Mindustry();