Merge branch 'master' of https://github.com/Anuken/Mindustry
This commit is contained in:
@@ -105,6 +105,8 @@ public class Vars{
|
||||
public static FileHandle screenshotDirectory;
|
||||
/** data subdirectory used for custom mmaps */
|
||||
public static FileHandle customMapDirectory;
|
||||
/** tmp subdirectory for map conversion */
|
||||
public static FileHandle tmpDirectory;
|
||||
/** data subdirectory used for saves */
|
||||
public static FileHandle saveDirectory;
|
||||
/** old map file extension, for conversion */
|
||||
@@ -206,5 +208,6 @@ public class Vars{
|
||||
screenshotDirectory = dataDirectory.child("screenshots/");
|
||||
customMapDirectory = dataDirectory.child("maps/");
|
||||
saveDirectory = dataDirectory.child("saves/");
|
||||
tmpDirectory = dataDirectory.child("tmp/");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.collection.IntQueue;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
@@ -40,6 +39,10 @@ public class Pathfinder{
|
||||
});
|
||||
}
|
||||
|
||||
public void updateSolid(Tile tile){
|
||||
update(tile, tile.getTeam());
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(Net.client() || paths == null) return;
|
||||
|
||||
@@ -95,6 +98,10 @@ public class Pathfinder{
|
||||
if(paths != null && paths[team.ordinal()] != null && paths[team.ordinal()].weights != null){
|
||||
PathData path = paths[team.ordinal()];
|
||||
|
||||
if(!path.frontier.isEmpty()){
|
||||
return;
|
||||
}
|
||||
|
||||
//impassable tiles have a weight of float.max
|
||||
if(!passable(tile, team)){
|
||||
path.weights[tile.x][tile.y] = Float.MAX_VALUE;
|
||||
|
||||
@@ -14,12 +14,13 @@ import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class WaveSpawner{
|
||||
private Array<FlyerSpawn> flySpawns = new Array<>();
|
||||
private Array<GroundSpawn> groundSpawns = new Array<>();
|
||||
private Array<Tile> groundSpawns = new Array<>();
|
||||
private boolean spawning = false;
|
||||
|
||||
public WaveSpawner(){
|
||||
@@ -30,6 +31,10 @@ public class WaveSpawner{
|
||||
return groundSpawns.size;
|
||||
}
|
||||
|
||||
public Array<Tile> getGroundSpawns(){
|
||||
return groundSpawns;
|
||||
}
|
||||
|
||||
/** @return true if the player is near a ground spawn point. */
|
||||
public boolean playerNear(){
|
||||
return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius);
|
||||
@@ -59,9 +64,9 @@ public class WaveSpawner{
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
spawnX = spawn.x * tilesize;
|
||||
spawnY = spawn.y * tilesize;
|
||||
for(Tile spawn : groundSpawns){
|
||||
spawnX = spawn.worldx();
|
||||
spawnY = spawn.worldy();
|
||||
spread = tilesize * 2;
|
||||
|
||||
for(int i = 0; i < spawned; i++){
|
||||
@@ -102,10 +107,7 @@ public class WaveSpawner{
|
||||
}
|
||||
|
||||
private void addSpawns(int x, int y){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
groundSpawns.add(spawn);
|
||||
groundSpawns.add(world.tile(x, y));
|
||||
|
||||
FlyerSpawn fspawn = new FlyerSpawn();
|
||||
fspawn.angle = Angles.angle(world.width() / 2f, world.height() / 2f, x, y);
|
||||
|
||||
@@ -114,6 +114,9 @@ public class Blocks implements ContentList{
|
||||
}
|
||||
|
||||
spawn = new OverlayFloor("spawn"){
|
||||
{
|
||||
variants = 0;
|
||||
}
|
||||
public void draw(Tile tile){}
|
||||
};
|
||||
|
||||
@@ -496,19 +499,7 @@ public class Blocks implements ContentList{
|
||||
GenericCrafterEntity entity = tile.entity();
|
||||
|
||||
Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy());
|
||||
|
||||
float progress = 0.5f;
|
||||
|
||||
Shaders.build.region = reg(weaveRegion);
|
||||
Shaders.build.progress = progress;
|
||||
Shaders.build.color.set(Pal.accent);
|
||||
Shaders.build.color.a = entity.warmup;
|
||||
Shaders.build.time = -entity.totalProgress / 10f;
|
||||
|
||||
Draw.shader(Shaders.build, false);
|
||||
Shaders.build.apply();
|
||||
Draw.rect(reg(weaveRegion), tile.drawx(), tile.drawy(), entity.totalProgress);
|
||||
Draw.shader();
|
||||
|
||||
Draw.color(Pal.accent);
|
||||
Draw.alpha(entity.warmup);
|
||||
@@ -940,7 +931,7 @@ public class Blocks implements ContentList{
|
||||
itemCapacity = 120;
|
||||
reloadTime = 200f;
|
||||
range = 440f;
|
||||
consumes.power(2f);
|
||||
consumes.power(1.75f);
|
||||
}};
|
||||
|
||||
//endregion
|
||||
@@ -1299,8 +1290,8 @@ public class Blocks implements ContentList{
|
||||
Items.scrap, Bullets.flakScrap,
|
||||
Items.lead, Bullets.flakLead
|
||||
);
|
||||
reload = 15f;
|
||||
range = 180f;
|
||||
reload = 16f;
|
||||
range = 175f;
|
||||
size = 2;
|
||||
burstSpacing = 5f;
|
||||
shots = 2;
|
||||
@@ -1499,7 +1490,7 @@ public class Blocks implements ContentList{
|
||||
ammo(Items.graphite, Bullets.fuseShot);
|
||||
reload = 40f;
|
||||
shootShake = 4f;
|
||||
range = 80f;
|
||||
range = 110f;
|
||||
recoil = 5f;
|
||||
restitution = 0.1f;
|
||||
size = 3;
|
||||
@@ -1544,7 +1535,7 @@ public class Blocks implements ContentList{
|
||||
reload = 50f;
|
||||
firingMoveFract = 0.5f;
|
||||
shootDuration = 220f;
|
||||
powerUse = 10f;
|
||||
powerUse = 14f;
|
||||
|
||||
health = 200 * size * size;
|
||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.5f)).update(false);
|
||||
|
||||
@@ -579,11 +579,12 @@ public class Bullets implements ContentList{
|
||||
|
||||
fuseShot = new BulletType(0.01f, 70){
|
||||
int rays = 3;
|
||||
float rayLength = 80f;
|
||||
float rayLength = 120f;
|
||||
|
||||
{
|
||||
hitEffect = Fx.hitFuse;
|
||||
lifetime = 13f;
|
||||
shootEffect = smokeEffect = Fx.none;
|
||||
lifetime = 10f;
|
||||
despawnEffect = Fx.none;
|
||||
pierce = true;
|
||||
}
|
||||
@@ -599,14 +600,15 @@ public class Bullets implements ContentList{
|
||||
public void draw(Bullet b){
|
||||
super.draw(b);
|
||||
Draw.color(Color.WHITE, Pal.surge, b.fin());
|
||||
//Draw.alpha(b.fout());
|
||||
for(int i = 0; i < 7; i++){
|
||||
Tmp.v1.trns(b.rot(), i * 8f);
|
||||
float sl = Mathf.clamp(b.fout() - 0.5f) * (80f - i * 10);
|
||||
Shapes.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, 4f, sl, b.rot() + 90);
|
||||
Shapes.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, 4f, sl, b.rot() - 90);
|
||||
}
|
||||
Shapes.tri(b.x, b.y, 13f, (rayLength + 50) * b.fout(), b.rot());
|
||||
Shapes.tri(b.x, b.y, 13f, 10f * b.fout(), b.rot() + 180f);
|
||||
Shapes.tri(b.x, b.y, 20f * b.fout(), (rayLength + 50), b.rot());
|
||||
Shapes.tri(b.x, b.y, 20f * b.fout(), 10f, b.rot() + 180f);
|
||||
Draw.reset();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ public class Mechs implements ContentList{
|
||||
boostSpeed = 0.95f;
|
||||
buildPower = 1.2f;
|
||||
engineColor = Color.valueOf("ffd37f");
|
||||
health = 300f;
|
||||
health = 250f;
|
||||
|
||||
weapon = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
@@ -51,10 +51,6 @@ public class Mechs implements ContentList{
|
||||
player.healBy(Time.delta() * 0.09f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysUnlocked(){
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
delta = new Mech("delta-mech", false){
|
||||
@@ -66,7 +62,7 @@ public class Mechs implements ContentList{
|
||||
boostSpeed = 0.95f;
|
||||
itemCapacity = 15;
|
||||
mass = 0.9f;
|
||||
health = 250f;
|
||||
health = 150f;
|
||||
buildPower = 0.9f;
|
||||
weaponOffsetX = -1;
|
||||
weaponOffsetY = -1;
|
||||
@@ -75,7 +71,7 @@ public class Mechs implements ContentList{
|
||||
weapon = new Weapon("shockgun"){{
|
||||
shake = 2f;
|
||||
length = 1f;
|
||||
reload = 40f;
|
||||
reload = 45f;
|
||||
shotDelay = 3f;
|
||||
roundrobin = true;
|
||||
shots = 2;
|
||||
@@ -163,12 +159,12 @@ public class Mechs implements ContentList{
|
||||
weaponOffsetX = 1;
|
||||
weaponOffsetY = 0;
|
||||
engineColor = Color.valueOf("feb380");
|
||||
health = 300f;
|
||||
health = 320f;
|
||||
buildPower = 1.5f;
|
||||
weapon = new Weapon("swarmer"){{
|
||||
length = 1.5f;
|
||||
recoil = 4f;
|
||||
reload = 60f;
|
||||
reload = 45f;
|
||||
shots = 4;
|
||||
spacing = 8f;
|
||||
inaccuracy = 8f;
|
||||
@@ -240,6 +236,11 @@ public class Mechs implements ContentList{
|
||||
bullet = Bullets.standardCopper;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysUnlocked(){
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
javelin = new Mech("javelin-ship", true){
|
||||
@@ -316,7 +317,7 @@ public class Mechs implements ContentList{
|
||||
itemCapacity = 30;
|
||||
engineColor = Color.valueOf("84f491");
|
||||
cellTrnsY = 1f;
|
||||
buildPower = 2f;
|
||||
buildPower = 2.5f;
|
||||
weapon = new Weapon("bomber"){{
|
||||
length = 0f;
|
||||
width = 2f;
|
||||
@@ -329,7 +330,7 @@ public class Mechs implements ContentList{
|
||||
velocityRnd = 1f;
|
||||
inaccuracy = 20f;
|
||||
ignoreRotation = true;
|
||||
bullet = new BombBulletType(14f, 25f, "shell"){{
|
||||
bullet = new BombBulletType(16f, 25f, "shell"){{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 14f;
|
||||
hitEffect = Fx.flakExplosion;
|
||||
|
||||
@@ -135,7 +135,7 @@ public class Control implements ApplicationListener{
|
||||
Net.host(port);
|
||||
player.isAdmin = true;
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true)));
|
||||
Core.app.post(() -> state.set(State.menu));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
player.remove();
|
||||
netServer.connections.remove(player.con.id);
|
||||
Log.info("&lc{0} has disconnected.", player.name);
|
||||
Log.info("&lm[{1}] &lc{0} has disconnected.", player.name, player.uuid);
|
||||
}
|
||||
|
||||
private static float compound(float speed, float drag){
|
||||
@@ -248,16 +248,16 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
@Remote(targets = Loc.client, unreliable = true)
|
||||
public static void onClientShapshot(
|
||||
Player player,
|
||||
int snapshotID,
|
||||
float x, float y,
|
||||
float pointerX, float pointerY,
|
||||
float rotation, float baseRotation,
|
||||
float xVelocity, float yVelocity,
|
||||
Tile mining,
|
||||
boolean boosting, boolean shooting, boolean chatting,
|
||||
BuildRequest[] requests,
|
||||
float viewX, float viewY, float viewWidth, float viewHeight
|
||||
Player player,
|
||||
int snapshotID,
|
||||
float x, float y,
|
||||
float pointerX, float pointerY,
|
||||
float rotation, float baseRotation,
|
||||
float xVelocity, float yVelocity,
|
||||
Tile mining,
|
||||
boolean boosting, boolean shooting, boolean chatting,
|
||||
BuildRequest[] requests,
|
||||
float viewX, float viewY, float viewWidth, float viewHeight
|
||||
){
|
||||
NetConnection connection = player.con;
|
||||
if(connection == null || snapshotID < connection.lastRecievedClientSnapshot) return;
|
||||
@@ -296,7 +296,7 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
vector.set(x - player.getInterpolator().target.x, y - player.getInterpolator().target.y);
|
||||
vector.limit(maxMove);
|
||||
//vector.limit(maxMove);
|
||||
|
||||
float prevx = player.x, prevy = player.y;
|
||||
player.set(player.getInterpolator().target.x, player.getInterpolator().target.y);
|
||||
@@ -372,7 +372,7 @@ public class NetServer implements ApplicationListener{
|
||||
player.add();
|
||||
player.con.hasConnected = true;
|
||||
Call.sendMessage("[accent]" + player.name + "[accent] has connected.");
|
||||
Log.info("&y{0} has connected.", player.name);
|
||||
Log.info("&lm[{1}] &y{0} has connected. ", player.name, player.uuid);
|
||||
}
|
||||
|
||||
public boolean isWaitingForPlayers(){
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Input.TextInput;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.math.RandomXS128;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.util.serialization.Base64Coder;
|
||||
@@ -66,14 +67,14 @@ public abstract class Platform{
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a file chooser. Desktop only.
|
||||
* Show a file chooser.
|
||||
* @param text File chooser title text
|
||||
* @param content Description of the type of files to be loaded
|
||||
* @param cons Selection listener
|
||||
* @param open Whether to open or save files
|
||||
* @param filetype File extension to filter
|
||||
*/
|
||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){
|
||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, Predicate<String> filetype){
|
||||
}
|
||||
|
||||
/** Hide the app. Android only. */
|
||||
|
||||
@@ -25,8 +25,7 @@ import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.ui.fragments.*;
|
||||
|
||||
import static io.anuke.arc.scene.actions.Actions.*;
|
||||
import static io.anuke.mindustry.Vars.control;
|
||||
import static io.anuke.mindustry.Vars.disableUI;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class UI implements ApplicationListener{
|
||||
private FreeTypeFontGenerator generator;
|
||||
@@ -244,8 +243,17 @@ public class UI implements ApplicationListener{
|
||||
}
|
||||
|
||||
public void showError(String text){
|
||||
new Dialog("$error.title", "dialog"){{
|
||||
cont.margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
new Dialog("", "dialog"){{
|
||||
setFillParent(true);
|
||||
cont.add("$error.title");
|
||||
cont.row();
|
||||
cont.margin(15).pane(t -> {
|
||||
Label l = t.add(text).pad(14f).get();
|
||||
l.setAlignment(Align.center, Align.left);
|
||||
if(mobile){
|
||||
t.getCell(l).wrap().width(400f);
|
||||
}
|
||||
});
|
||||
buttons.addButton("$ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
@@ -12,8 +12,13 @@ import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class DrawOperation{
|
||||
private MapEditor editor;
|
||||
private LongArray array = new LongArray();
|
||||
|
||||
public DrawOperation(MapEditor editor) {
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return array.isEmpty();
|
||||
}
|
||||
@@ -22,23 +27,25 @@ public class DrawOperation{
|
||||
array.add(op);
|
||||
}
|
||||
|
||||
public void undo(MapEditor editor){
|
||||
public void undo(){
|
||||
for(int i = array.size - 1; i >= 0; i--){
|
||||
long l = array.get(i);
|
||||
array.set(i, TileOp.get(TileOp.x(l), TileOp.y(l), TileOp.type(l), get(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l))));
|
||||
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.value(l));
|
||||
updateTile(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(MapEditor editor){
|
||||
public void redo(){
|
||||
for(int i = 0; i < array.size; i++){
|
||||
long l = array.get(i);
|
||||
array.set(i, TileOp.get(TileOp.x(l), TileOp.y(l), TileOp.type(l), get(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l))));
|
||||
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.value(l));
|
||||
updateTile(i);
|
||||
}
|
||||
}
|
||||
|
||||
short get(Tile tile, byte type){
|
||||
private void updateTile(int i) {
|
||||
long l = array.get(i);
|
||||
array.set(i, TileOp.get(TileOp.x(l), TileOp.y(l), TileOp.type(l), getTile(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l))));
|
||||
setTile(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.value(l));
|
||||
}
|
||||
|
||||
short getTile(Tile tile, byte type){
|
||||
if(type == OpType.floor.ordinal()){
|
||||
return tile.floorID();
|
||||
}else if(type == OpType.block.ordinal()){
|
||||
@@ -53,7 +60,7 @@ public class DrawOperation{
|
||||
throw new IllegalArgumentException("Invalid type.");
|
||||
}
|
||||
|
||||
void set(MapEditor editor, Tile tile, byte type, short to){
|
||||
void setTile(Tile tile, byte type, short to){
|
||||
editor.load(() -> {
|
||||
if(type == OpType.floor.ordinal()){
|
||||
tile.setFloor((Floor)content.block(to));
|
||||
|
||||
@@ -99,7 +99,7 @@ public class EditorTile extends Tile{
|
||||
}
|
||||
|
||||
if(overlayID() == overlay) return;
|
||||
op(OpType.overlay, overlay);
|
||||
op(OpType.overlay, this.overlay);
|
||||
super.setOverlayID(overlay);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public enum EditorTool{
|
||||
|
||||
IntArray stack = new IntArray();
|
||||
Block dest;
|
||||
boolean isfloor;
|
||||
boolean isFloor;
|
||||
MapEditor data;
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
@@ -64,14 +64,14 @@ public enum EditorTool{
|
||||
}
|
||||
|
||||
data = editor;
|
||||
isfloor = editor.drawBlock instanceof Floor;
|
||||
isFloor = editor.drawBlock instanceof Floor;
|
||||
|
||||
Block floor = tile.floor();
|
||||
Block block = tile.block();
|
||||
boolean synth = editor.drawBlock.synthetic();
|
||||
|
||||
Block draw = editor.drawBlock;
|
||||
dest = draw instanceof OverlayFloor ? tile.overlay() : isfloor ? floor : block;
|
||||
dest = draw instanceof OverlayFloor ? tile.overlay() : isFloor ? floor : block;
|
||||
|
||||
if(dest == draw || block instanceof BlockPart || block.isMultiblock()){
|
||||
return;
|
||||
@@ -85,7 +85,7 @@ public enum EditorTool{
|
||||
IntPositionConsumer writer = (px, py) -> {
|
||||
Tile write = editor.tile(px, py);
|
||||
|
||||
if(isfloor){
|
||||
if(isFloor){
|
||||
if(alt && !(draw instanceof OverlayFloor)){
|
||||
Block ore = write.overlay();
|
||||
write.setFloor((Floor)draw);
|
||||
@@ -167,7 +167,7 @@ public enum EditorTool{
|
||||
boolean eq(int px, int py){
|
||||
Tile tile = data.tile(px, py);
|
||||
|
||||
return (data.drawBlock instanceof OverlayFloor ? tile.overlay() : isfloor ? tile.floor() : tile.block()) == dest && !(data.drawBlock instanceof OverlayFloor && tile.floor().isLiquid);
|
||||
return (data.drawBlock instanceof OverlayFloor ? tile.overlay() : isFloor ? tile.floor() : tile.block()) == dest && !(data.drawBlock instanceof OverlayFloor && tile.floor().isLiquid);
|
||||
}
|
||||
},
|
||||
spray{
|
||||
|
||||
@@ -240,13 +240,13 @@ public class MapEditor{
|
||||
|
||||
public void undo(){
|
||||
if(stack.canUndo()){
|
||||
stack.undo(this);
|
||||
stack.undo();
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(){
|
||||
if(stack.canRedo()){
|
||||
stack.redo(this);
|
||||
stack.redo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public class MapEditor{
|
||||
public void addTileOp(long data){
|
||||
if(loading) return;
|
||||
|
||||
if(currentOp == null) currentOp = new DrawOperation();
|
||||
if(currentOp == null) currentOp = new DrawOperation(this);
|
||||
currentOp.addOperation(data);
|
||||
|
||||
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
|
||||
|
||||
@@ -21,9 +21,9 @@ import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.io.JsonIO;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.ui.dialogs.FileChooser;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
@@ -93,14 +93,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable)loadDialog::show,
|
||||
"$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable)() ->
|
||||
Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> {
|
||||
try{
|
||||
//TODO what if it's an image? users should be warned for their stupidity
|
||||
editor.beginEdit(MapIO.createMap(file, true));
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
}), true, mapExtension),
|
||||
world.maps.tryCatchMapError(() -> {
|
||||
if(MapIO.isImage(file)){
|
||||
ui.showInfo("$editor.errorimage");
|
||||
}else if(file.extension().equalsIgnoreCase(oldMapExtension)){
|
||||
editor.beginEdit(world.maps.makeLegacyMap(file));
|
||||
}else{
|
||||
editor.beginEdit(MapIO.createMap(file, true));
|
||||
}
|
||||
});
|
||||
}), true, FileChooser.anyMapFiles),
|
||||
|
||||
"$editor.importimage", "$editor.importimage.description", "icon-file-image", (Runnable)() ->
|
||||
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
|
||||
@@ -110,10 +112,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
editor.beginEdit(pixmap);
|
||||
pixmap.dispose();
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true)));
|
||||
Log.err(e);
|
||||
}
|
||||
}), true, "png"))
|
||||
}), true, FileChooser.pngFiles))
|
||||
);
|
||||
|
||||
t.addImageTextButton("$editor.export", "icon-save-map", isize, () ->
|
||||
@@ -127,11 +129,11 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
MapIO.writeMap(result, editor.createMap(result));
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, true)));
|
||||
Log.err(e);
|
||||
}
|
||||
});
|
||||
}, false, mapExtension));
|
||||
}, false, FileChooser.mapFiles));
|
||||
});
|
||||
|
||||
menu.cont.row();
|
||||
@@ -153,12 +155,11 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
});
|
||||
|
||||
loadDialog = new MapLoadDialog(map ->
|
||||
ui.loadAnd(() -> {
|
||||
loadDialog = new MapLoadDialog(map -> ui.loadAnd(() -> {
|
||||
try{
|
||||
editor.beginEdit(map);
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true)));
|
||||
Log.err(e);
|
||||
}
|
||||
}));
|
||||
@@ -188,13 +189,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
});
|
||||
|
||||
shown(() -> {
|
||||
//clear units, rules and other unnecessary stuff
|
||||
logic.reset();
|
||||
|
||||
saved = true;
|
||||
if(!Core.settings.getBool("landscape")) Platform.instance.beginForceLandscape();
|
||||
editor.clearOp();
|
||||
Core.scene.setScrollFocus(view);
|
||||
if(!shownWithMap){
|
||||
//clear units, rules and other unnecessary stuff
|
||||
logic.reset();
|
||||
state.rules = new Rules();
|
||||
editor.beginEdit(200, 200);
|
||||
}
|
||||
@@ -231,7 +233,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
hide();
|
||||
//only reset the player; logic.reset() will clear entities, which we do not want
|
||||
player.reset();
|
||||
state.rules = Gamemode.editor.apply(new Rules());
|
||||
state.rules = Gamemode.editor.apply(lastSavedRules.copy());
|
||||
world.setMap(new Map(StringMap.of(
|
||||
"name", "Editor Playtesting",
|
||||
"width", editor.width(),
|
||||
@@ -256,6 +258,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
private void save(){
|
||||
String name = editor.getTags().get("name", "").trim();
|
||||
editor.getTags().put("rules", JsonIO.write(state.rules));
|
||||
player.dead = true;
|
||||
|
||||
if(name.isEmpty()){
|
||||
infoDialog.show();
|
||||
@@ -335,7 +338,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
show();
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,21 +27,22 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MapGenerateDialog extends FloatingDialog{
|
||||
private final Supplier<GenerateFilter>[] filterTypes = new Supplier[]{NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new, OreFilter::new, MedianFilter::new};
|
||||
private final MapEditor editor;
|
||||
|
||||
private Pixmap pixmap;
|
||||
private Texture texture;
|
||||
private GenerateInput input = new GenerateInput();
|
||||
private Array<GenerateFilter> filters = new Array<>();
|
||||
private int scaling = mobile ? 3 : 1;
|
||||
private Supplier<GenerateFilter>[] filterTypes = new Supplier[]{NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new, OreFilter::new};
|
||||
private Table filterTable;
|
||||
|
||||
private AsyncExecutor executor = new AsyncExecutor(1);
|
||||
private AsyncResult<Void> result;
|
||||
private boolean generating;
|
||||
private DummyTile returnTile = new DummyTile();
|
||||
private GenTile returnTile = new GenTile();
|
||||
|
||||
private DummyTile[][] buffer1, buffer2;
|
||||
private GenTile[][] buffer1, buffer2;
|
||||
|
||||
public MapGenerateDialog(MapEditor editor){
|
||||
super("$editor.generate");
|
||||
@@ -98,12 +99,12 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
rebuildFilters();
|
||||
}
|
||||
|
||||
DummyTile[][] create(){
|
||||
DummyTile[][] out = new DummyTile[editor.width() / scaling][editor.height() / scaling];
|
||||
GenTile[][] create(){
|
||||
GenTile[][] out = new GenTile[editor.width() / scaling][editor.height() / scaling];
|
||||
|
||||
for(int x = 0; x < out.length; x++){
|
||||
for(int y = 0; y < out[0].length; y++){
|
||||
out[x][y] = new DummyTile();
|
||||
out[x][y] = new GenTile();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
@@ -187,7 +188,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
selection.show();
|
||||
}
|
||||
|
||||
DummyTile dset(Tile tile){
|
||||
GenTile dset(Tile tile){
|
||||
returnTile.set(tile);
|
||||
return returnTile;
|
||||
}
|
||||
@@ -208,11 +209,11 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
//writeback buffer
|
||||
DummyTile[][] writeTiles = new DummyTile[editor.width()][editor.height()];
|
||||
GenTile[][] writeTiles = new GenTile[editor.width()][editor.height()];
|
||||
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
writeTiles[x][y] = new DummyTile();
|
||||
writeTiles[x][y] = new GenTile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +234,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
Tile tile = editor.tile(x, y);
|
||||
DummyTile write = writeTiles[x][y];
|
||||
GenTile write = writeTiles[x][y];
|
||||
|
||||
tile.rotation(write.rotation);
|
||||
tile.setFloor((Floor)content.block(write.floor));
|
||||
@@ -278,7 +279,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
for(int px = 0; px < pixmap.getWidth(); px++){
|
||||
for(int py = 0; py < pixmap.getHeight(); py++){
|
||||
int x = px * scaling, y = py * scaling;
|
||||
DummyTile tile = buffer1[px][py];
|
||||
GenTile tile = buffer1[px][py];
|
||||
input.begin(editor, x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore));
|
||||
filter.apply(input);
|
||||
buffer2[px][py].set(input.floor, input.block, input.ore, Team.all[tile.team], tile.rotation);
|
||||
@@ -299,7 +300,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
Tile tile = editor.tile(px * scaling, py * scaling);
|
||||
color = MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), Team.none);
|
||||
}else{
|
||||
DummyTile tile = buffer1[px][py];
|
||||
GenTile tile = buffer1[px][py];
|
||||
color = MapIO.colorFor(content.block(tile.floor), content.block(tile.block), content.block(tile.ore), Team.none);
|
||||
}
|
||||
pixmap.drawPixel(px, pixmap.getHeight() - 1 - py, color);
|
||||
@@ -321,7 +322,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
});
|
||||
}
|
||||
|
||||
public static class DummyTile{
|
||||
public static class GenTile{
|
||||
public byte team, rotation;
|
||||
public short block, floor, ore;
|
||||
|
||||
@@ -333,7 +334,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
||||
this.rotation = (byte)rotation;
|
||||
}
|
||||
|
||||
void set(DummyTile other){
|
||||
void set(GenTile other){
|
||||
this.floor = other.floor;
|
||||
this.block = other.block;
|
||||
this.ore = other.ore;
|
||||
|
||||
@@ -12,13 +12,13 @@ import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
|
||||
public class MapInfoDialog extends FloatingDialog{
|
||||
private final MapEditor editor;
|
||||
private final WaveInfoDialog waveinfo;
|
||||
private final CustomRulesDialog ruleinfo = new CustomRulesDialog();
|
||||
private final WaveInfoDialog waveInfo;
|
||||
private final CustomRulesDialog ruleInfo = new CustomRulesDialog();
|
||||
|
||||
public MapInfoDialog(MapEditor editor){
|
||||
super("$editor.mapinfo");
|
||||
this.editor = editor;
|
||||
this.waveinfo = new WaveInfoDialog(editor);
|
||||
this.waveInfo = new WaveInfoDialog(editor);
|
||||
|
||||
addCloseButton();
|
||||
|
||||
@@ -58,11 +58,11 @@ public class MapInfoDialog extends FloatingDialog{
|
||||
|
||||
cont.row();
|
||||
cont.add("$editor.rules").padRight(8).left();
|
||||
cont.addButton("$edit", () -> ruleinfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f);;
|
||||
cont.addButton("$edit", () -> ruleInfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f);;
|
||||
|
||||
cont.row();
|
||||
cont.add("$editor.waves").padRight(8).left();
|
||||
cont.addButton("$edit", waveinfo::show).left().width(200f);
|
||||
cont.addButton("$edit", waveInfo::show).left().width(200f);
|
||||
|
||||
name.change();
|
||||
description.change();
|
||||
|
||||
@@ -19,7 +19,7 @@ import io.anuke.mindustry.world.blocks.BlockPart;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class MapRenderer implements Disposable{
|
||||
private static final int chunksize = 64;
|
||||
private static final int chunkSize = 64;
|
||||
private IndexedRenderer[][] chunks;
|
||||
private IntSet updates = new IntSet();
|
||||
private IntSet delayedUpdates = new IntSet();
|
||||
@@ -41,11 +41,11 @@ public class MapRenderer implements Disposable{
|
||||
}
|
||||
}
|
||||
|
||||
chunks = new IndexedRenderer[(int)Math.ceil((float)width / chunksize)][(int)Math.ceil((float)height / chunksize)];
|
||||
chunks = new IndexedRenderer[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)];
|
||||
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
chunks[x][y] = new IndexedRenderer(chunksize * chunksize * 2);
|
||||
chunks[x][y] = new IndexedRenderer(chunkSize * chunkSize * 2);
|
||||
}
|
||||
}
|
||||
this.width = width;
|
||||
@@ -97,7 +97,7 @@ public class MapRenderer implements Disposable{
|
||||
}
|
||||
|
||||
private void render(int wx, int wy){
|
||||
int x = wx / chunksize, y = wy / chunksize;
|
||||
int x = wx / chunkSize, y = wy / chunkSize;
|
||||
IndexedRenderer mesh = chunks[x][y];
|
||||
Tile tile = editor.tiles()[wx][wy];
|
||||
|
||||
@@ -107,8 +107,8 @@ public class MapRenderer implements Disposable{
|
||||
|
||||
TextureRegion region;
|
||||
|
||||
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
||||
int idxWall = (wx % chunkSize) + (wy % chunkSize) * chunkSize;
|
||||
int idxDecal = (wx % chunkSize) + (wy % chunkSize) * chunkSize + chunkSize * chunkSize;
|
||||
|
||||
if(wall != Blocks.air && (wall.synthetic() || wall instanceof BlockPart)){
|
||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||
@@ -145,8 +145,8 @@ public class MapRenderer implements Disposable{
|
||||
}
|
||||
|
||||
mesh.draw(idxDecal, region,
|
||||
wx * tilesize + offsetX, wy * tilesize + offsetY,
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl);
|
||||
wx * tilesize + offsetX, wy * tilesize + offsetY,
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl);
|
||||
mesh.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,18 +34,18 @@ public class OperationStack{
|
||||
return !(index > -1 || stack.size + index < 0);
|
||||
}
|
||||
|
||||
public void undo(MapEditor editor){
|
||||
public void undo(){
|
||||
if(!canUndo()) return;
|
||||
|
||||
stack.get(stack.size - 1 + index).undo(editor);
|
||||
stack.get(stack.size - 1 + index).undo();
|
||||
index--;
|
||||
}
|
||||
|
||||
public void redo(MapEditor editor){
|
||||
public void redo(){
|
||||
if(!canRedo()) return;
|
||||
|
||||
index++;
|
||||
stack.get(stack.size - 1 + index).redo(editor);
|
||||
stack.get(stack.size - 1 + index).redo();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.DummyTile;
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.GenTile;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.SliderOption;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
@@ -11,14 +11,14 @@ public class DistortFilter extends GenerateFilter{
|
||||
|
||||
{
|
||||
options(
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 400f),
|
||||
new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f)
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 400f),
|
||||
new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
DummyTile tile = in.tile(in.x / (in.scaling) + (noise(in.x, in.y, scl, mag) - mag / 2f) / in.scaling, in.y / (in.scaling) + (noise(in.x, in.y + o, scl, mag) - mag / 2f) / in.scaling);
|
||||
GenTile tile = in.tile(in.x / (in.scaling) + (noise(in.x, in.y, scl, mag) - mag / 2f) / in.scaling, in.y / (in.scaling) + (noise(in.x, in.y + o, scl, mag) - mag / 2f) / in.scaling);
|
||||
|
||||
in.floor = content.block(tile.floor);
|
||||
if(!content.block(tile.block).synthetic() && !in.block.synthetic()) in.block = content.block(tile.block);
|
||||
|
||||
@@ -7,14 +7,14 @@ import io.anuke.arc.util.noise.RidgedPerlin;
|
||||
import io.anuke.arc.util.noise.Simplex;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.editor.MapEditor;
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.DummyTile;
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.GenTile;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
public abstract class GenerateFilter{
|
||||
protected float o = (float)(Math.random() * 10000000.0);
|
||||
protected long seed;
|
||||
protected GenerateInput in;
|
||||
protected transient float o = (float)(Math.random() * 10000000.0);
|
||||
protected transient long seed;
|
||||
protected transient GenerateInput in;
|
||||
|
||||
public FilterOption[] options;
|
||||
|
||||
@@ -88,12 +88,12 @@ public abstract class GenerateFilter{
|
||||
pnoise.setSeed((int)(filter.seed + 1));
|
||||
}
|
||||
|
||||
DummyTile tile(float x, float y){
|
||||
GenTile tile(float x, float y){
|
||||
return buffer.get(Mathf.clamp((int)x, 0, width - 1), Mathf.clamp((int)y, 0, height - 1));
|
||||
}
|
||||
|
||||
public interface TileProvider{
|
||||
DummyTile get(int x, int y);
|
||||
GenTile get(int x, int y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.GenTile;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.SliderOption;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class MedianFilter extends GenerateFilter{
|
||||
float radius = 2;
|
||||
float percentile = 0.5f;
|
||||
IntArray blocks = new IntArray(), floors = new IntArray();
|
||||
|
||||
{
|
||||
options(
|
||||
new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f),
|
||||
new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
int rad = (int)radius;
|
||||
blocks.clear();
|
||||
floors.clear();
|
||||
for(int x = -rad; x <= rad; x++){
|
||||
for(int y = -rad; y <= rad; y++){
|
||||
if(Mathf.dst2(x, y) > rad*rad) continue;
|
||||
|
||||
GenTile tile = in.tile(in.x + x, in.y + y);
|
||||
blocks.add(tile.block);
|
||||
floors.add(tile.floor);
|
||||
}
|
||||
}
|
||||
|
||||
floors.sort();
|
||||
blocks.sort();
|
||||
|
||||
int index = Math.min((int)(floors.size * percentile), floors.size - 1);
|
||||
int floor = floors.get(index), block = blocks.get(index);
|
||||
|
||||
in.floor = content.block(floor);
|
||||
if(!content.block(block).synthetic() && !in.block.synthetic()) in.block = content.block(block);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ public class LiquidBulletType extends BulletType{
|
||||
statusDuration = 90f;
|
||||
despawnEffect = Fx.none;
|
||||
hitEffect = Fx.hitLiquid;
|
||||
smokeEffect = Fx.none;
|
||||
shootEffect = Fx.none;
|
||||
drag = 0.009f;
|
||||
knockback = 0.55f;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.TimedEntity;
|
||||
import io.anuke.mindustry.entities.traits.BelowLiquidTrait;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
import static io.anuke.mindustry.Vars.groundEffectGroup;
|
||||
|
||||
@@ -14,7 +14,6 @@ import static io.anuke.mindustry.Vars.groundEffectGroup;
|
||||
* Class for creating block rubble on the ground.
|
||||
*/
|
||||
public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{
|
||||
private static final Color color = Color.valueOf("3a3635");
|
||||
|
||||
@Override
|
||||
public float lifetime(){
|
||||
@@ -23,7 +22,7 @@ public abstract class Decal extends TimedEntity implements BelowLiquidTrait, Dra
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.color(color.r, color.g, color.b, 1f - Mathf.curve(fin(), 0.98f));
|
||||
Draw.color(Pal.rubble.r, Pal.rubble.g, Pal.rubble.b, 1f - Mathf.curve(fin(), 0.98f));
|
||||
drawDecal();
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.pooling.Pool.Poolable;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.impl.TimedEntity;
|
||||
@@ -22,7 +20,7 @@ import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
public class Fire extends TimedEntity implements SaveTrait, SyncTrait{
|
||||
private static final IntMap<Fire> map = new IntMap<>();
|
||||
private static final float baseLifetime = 1000f, spreadChance = 0.05f, fireballChance = 0.07f;
|
||||
|
||||
@@ -36,6 +34,11 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
public Fire(){
|
||||
}
|
||||
|
||||
@Remote
|
||||
public static void onRemoveFire(int fid){
|
||||
fireGroup.removeByID(fid);
|
||||
}
|
||||
|
||||
/** Start a fire on the tile. If there already is a file there, refreshes its lifetime. */
|
||||
public static void create(Tile tile){
|
||||
if(Net.client() || tile == null) return; //not clientside.
|
||||
@@ -43,7 +46,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
Fire fire = map.get(tile.pos());
|
||||
|
||||
if(fire == null){
|
||||
fire = Pools.obtain(Fire.class, Fire::new);
|
||||
fire = new Fire();
|
||||
fire.tile = tile;
|
||||
fire.lifetime = baseLifetime;
|
||||
fire.set(tile.worldx(), tile.worldy());
|
||||
@@ -94,12 +97,12 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
|
||||
time = Mathf.clamp(time + Time.delta(), 0, lifetime());
|
||||
|
||||
if(time >= lifetime() || tile == null){
|
||||
remove();
|
||||
if(Net.client()){
|
||||
return;
|
||||
}
|
||||
|
||||
if(Net.client()){
|
||||
if(time >= lifetime() || tile == null){
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,6 +179,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
|
||||
x = Pos.x(pos) * tilesize;
|
||||
y = Pos.y(pos) * tilesize;
|
||||
tile = world.tile(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,6 +188,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
tile = null;
|
||||
baseFlammability = -1;
|
||||
puddleFlammability = 0f;
|
||||
incrementID();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,9 +203,9 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
@Override
|
||||
public void removed(){
|
||||
if(tile != null){
|
||||
Call.onRemoveFire(id);
|
||||
map.remove(tile.pos());
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,4 +58,9 @@ public abstract class BaseEntity implements Entity{
|
||||
public String toString(){
|
||||
return getClass() + " " + id;
|
||||
}
|
||||
|
||||
/** Increments this entity's ID. Used for pooled entities.*/
|
||||
public void incrementID(){
|
||||
id = lastid++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
output.writeInt(Pos.get(request.x, request.y));
|
||||
output.writeFloat(request.progress);
|
||||
if(!request.breaking){
|
||||
output.writeByte(request.block.id);
|
||||
output.writeShort(request.block.id);
|
||||
output.writeByte(request.rotation);
|
||||
}
|
||||
}else{
|
||||
@@ -189,7 +189,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
if(type == 1){ //remove
|
||||
request = new BuildRequest(Pos.x(position), Pos.y(position));
|
||||
}else{ //place
|
||||
byte block = input.readByte();
|
||||
short block = input.readShort();
|
||||
byte rotation = input.readByte();
|
||||
request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.units.UnitFactory.UnitFactoryEntity;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
|
||||
import java.io.*;
|
||||
@@ -264,7 +265,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
|
||||
avoidOthers();
|
||||
|
||||
if(spawner != noSpawner && (world.tile(spawner) == null || world.tile(spawner).entity == null)){
|
||||
if(spawner != noSpawner && (world.tile(spawner) == null || !(world.tile(spawner).entity instanceof UnitFactoryEntity))){
|
||||
kill();
|
||||
}
|
||||
|
||||
|
||||
@@ -559,7 +559,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
||||
updateShooting(); //server simulates player shooting
|
||||
}
|
||||
return;
|
||||
}else{
|
||||
}else if(world.isZone()){
|
||||
//unlock mech when used
|
||||
data.unlockContent(mech);
|
||||
}
|
||||
@@ -665,10 +665,10 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
||||
attractDst = 0f;
|
||||
|
||||
if(tapping){
|
||||
velocity.setAngle(Mathf.slerpDelta(velocity.angle(), angleTo(moveTarget), 0.1f));
|
||||
velocity.setAngle(angleTo(moveTarget));
|
||||
}
|
||||
|
||||
if(dst(moveTarget) < 2f){
|
||||
if(dst(moveTarget) <= 2f * Time.delta()){
|
||||
if(tapping){
|
||||
Tile tile = ((TileEntity)moveTarget).tile;
|
||||
tile.block().tapped(tile, this);
|
||||
@@ -680,7 +680,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
||||
moveTarget = null;
|
||||
}
|
||||
|
||||
movement.set(targetX - x, targetY - y).limit(isBoosting && !mech.flying ? mech.boostSpeed : mech.speed);
|
||||
movement.set((targetX - x) / Time.delta(), (targetY - y) / Time.delta()).limit(isBoosting && !mech.flying ? mech.boostSpeed : mech.speed);
|
||||
movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f));
|
||||
|
||||
if(dst(targetX, targetY) < attractDst){
|
||||
@@ -795,7 +795,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
||||
}
|
||||
|
||||
public boolean isShooting(){
|
||||
return isShooting && (!isBoosting || mech.flying);
|
||||
return isShooting && (!isBoosting || mech.flying) && mining == null;
|
||||
}
|
||||
|
||||
public void updateRespawning(){
|
||||
|
||||
@@ -9,8 +9,7 @@ import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
@@ -256,6 +255,16 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
kill();
|
||||
}
|
||||
|
||||
//apply knockback based on spawns
|
||||
if(getTeam() != waveTeam){
|
||||
float relativeSize = state.rules.dropZoneRadius + getSize()/2f + 1f;
|
||||
for(Tile spawn : world.spawner.getGroundSpawns()){
|
||||
if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){
|
||||
velocity.add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isFlying()){
|
||||
drownTime = 0f;
|
||||
move(velocity.x * Time.delta(), velocity.y * Time.delta());
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.anuke.mindustry.game;
|
||||
|
||||
import io.anuke.arc.Events.Event;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
@@ -10,7 +9,7 @@ import io.anuke.mindustry.world.Tile;
|
||||
public class EventType{
|
||||
|
||||
/** Called when a zone's requirements are met. */
|
||||
public static class ZoneRequireCompleteEvent implements Event{
|
||||
public static class ZoneRequireCompleteEvent{
|
||||
public final Zone zone, required;
|
||||
|
||||
public ZoneRequireCompleteEvent(Zone zone, Zone required){
|
||||
@@ -20,7 +19,7 @@ public class EventType{
|
||||
}
|
||||
|
||||
/** Called when a zone's requirements are met. */
|
||||
public static class ZoneConfigureCompleteEvent implements Event{
|
||||
public static class ZoneConfigureCompleteEvent{
|
||||
public final Zone zone;
|
||||
|
||||
public ZoneConfigureCompleteEvent(Zone zone){
|
||||
@@ -29,23 +28,23 @@ public class EventType{
|
||||
}
|
||||
|
||||
/** Called when the game is first loaded. */
|
||||
public static class GameLoadEvent implements Event{
|
||||
public static class GameLoadEvent{
|
||||
|
||||
}
|
||||
|
||||
public static class PlayEvent implements Event{
|
||||
public static class PlayEvent{
|
||||
|
||||
}
|
||||
|
||||
public static class ResetEvent implements Event{
|
||||
public static class ResetEvent{
|
||||
|
||||
}
|
||||
|
||||
public static class WaveEvent implements Event{
|
||||
public static class WaveEvent{
|
||||
|
||||
}
|
||||
|
||||
public static class GameOverEvent implements Event{
|
||||
public static class GameOverEvent{
|
||||
public final Team winner;
|
||||
|
||||
public GameOverEvent(Team winner){
|
||||
@@ -54,12 +53,12 @@ public class EventType{
|
||||
}
|
||||
|
||||
/** Called when a game begins and the world is loaded. */
|
||||
public static class WorldLoadEvent implements Event{
|
||||
public static class WorldLoadEvent{
|
||||
|
||||
}
|
||||
|
||||
/** Called from the logic thread. Do not access graphics here! */
|
||||
public static class TileChangeEvent implements Event{
|
||||
public static class TileChangeEvent{
|
||||
public final Tile tile;
|
||||
|
||||
public TileChangeEvent(Tile tile){
|
||||
@@ -67,7 +66,7 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class StateChangeEvent implements Event{
|
||||
public static class StateChangeEvent{
|
||||
public final State from, to;
|
||||
|
||||
public StateChangeEvent(State from, State to){
|
||||
@@ -76,7 +75,7 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnlockEvent implements Event{
|
||||
public static class UnlockEvent{
|
||||
public final UnlockableContent content;
|
||||
|
||||
public UnlockEvent(UnlockableContent content){
|
||||
@@ -88,7 +87,7 @@ public class EventType{
|
||||
* Called when block building begins by placing down the BuildBlock.
|
||||
* The tile's block will nearly always be a BuildBlock.
|
||||
*/
|
||||
public static class BlockBuildBeginEvent implements Event{
|
||||
public static class BlockBuildBeginEvent{
|
||||
public final Tile tile;
|
||||
public final Team team;
|
||||
public final boolean breaking;
|
||||
@@ -100,7 +99,7 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockBuildEndEvent implements Event{
|
||||
public static class BlockBuildEndEvent{
|
||||
public final Tile tile;
|
||||
public final Team team;
|
||||
public final boolean breaking;
|
||||
@@ -116,7 +115,7 @@ public class EventType{
|
||||
* Called when a player or drone begins building something.
|
||||
* This does not necessarily happen when a new BuildBlock is created.
|
||||
*/
|
||||
public static class BuildSelectEvent implements Event{
|
||||
public static class BuildSelectEvent{
|
||||
public final Tile tile;
|
||||
public final Team team;
|
||||
public final BuilderTrait builder;
|
||||
@@ -130,7 +129,7 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockDestroyEvent implements Event{
|
||||
public static class BlockDestroyEvent{
|
||||
public final Tile tile;
|
||||
|
||||
public BlockDestroyEvent(Tile tile){
|
||||
@@ -138,7 +137,7 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnitDestroyEvent implements Event{
|
||||
public static class UnitDestroyEvent{
|
||||
public final Unit unit;
|
||||
|
||||
public UnitDestroyEvent(Unit unit){
|
||||
@@ -146,7 +145,7 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResizeEvent implements Event{
|
||||
public static class ResizeEvent{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +28,10 @@ public enum Gamemode{
|
||||
rules.respawnTime = 60 * 10;
|
||||
rules.buildCostMultiplier = 0.5f;
|
||||
rules.buildSpeedMultiplier = 2f;
|
||||
rules.playerDamageMultiplier = 0.45f;
|
||||
rules.playerHealthMultiplier = 0.8f;
|
||||
rules.playerDamageMultiplier = 0.33f;
|
||||
rules.playerHealthMultiplier = 0.5f;
|
||||
rules.unitBuildSpeedMultiplier = 3f;
|
||||
rules.unitHealthMultiplier = 2f;
|
||||
rules.unitHealthMultiplier = 3f;
|
||||
rules.attackMode = true;
|
||||
}),
|
||||
editor(true, rules -> {
|
||||
|
||||
@@ -28,7 +28,7 @@ public class Teams{
|
||||
/** Returns whether a team is active, e.g. whether it has any cores remaining. */
|
||||
public boolean isActive(Team team){
|
||||
//the enemy wave team is always active
|
||||
return (Vars.state.rules.waves && team == Vars.waveTeam) || get(team).cores.size > 0;
|
||||
return team == Vars.waveTeam || get(team).cores.size > 0;
|
||||
}
|
||||
|
||||
/** Returns a set of all teams that are enemies of this team. */
|
||||
|
||||
@@ -35,6 +35,7 @@ public class Pal{
|
||||
darkishGray = new Color(0.3f, 0.3f, 0.3f, 1f),
|
||||
darkerGray = new Color(0.2f, 0.2f, 0.2f, 1f),
|
||||
ammo = Color.valueOf("ff8947"),
|
||||
rubble = Color.valueOf("1c1817"),
|
||||
|
||||
boostTo = Color.valueOf("ffad4d"),
|
||||
boostFrom = Color.valueOf("ff7f57"),
|
||||
|
||||
@@ -40,6 +40,8 @@ public class LegacyMapIO{
|
||||
for(int x = 0; x < map.width; x++){
|
||||
for(int y = 0; y < map.height; y++){
|
||||
tiles[x][y] = new CachedTile();
|
||||
tiles[x][y].x = (short)x;
|
||||
tiles[x][y].y = (short)y;
|
||||
}
|
||||
}
|
||||
state.rules.spawns = groups;
|
||||
@@ -53,6 +55,9 @@ public class LegacyMapIO{
|
||||
|
||||
//meta is uncompressed
|
||||
int version = stream.readInt();
|
||||
if(version != 1){
|
||||
throw new IOException("Outdated legacy map format");
|
||||
}
|
||||
int build = stream.readInt();
|
||||
short width = stream.readShort(), height = stream.readShort();
|
||||
byte tagAmount = stream.readByte();
|
||||
|
||||
@@ -71,6 +71,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
|
||||
state.stats = JsonIO.read(Stats.class, map.get("stats", "{}"));
|
||||
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
|
||||
if(state.rules.spawns.isEmpty()) state.rules.spawns = DefaultWaves.get();
|
||||
Map worldmap = world.maps.byName(map.get("mapname", "\\\\\\"));
|
||||
world.setMap(worldmap == null ? new Map(StringMap.of(
|
||||
"name", map.get("mapname", "Unknown"),
|
||||
@@ -170,10 +171,14 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
tile.setBlock(block);
|
||||
|
||||
if(tile.entity != null){
|
||||
readChunk(stream, true, in -> {
|
||||
byte version = in.readByte();
|
||||
tile.entity.read(in, version);
|
||||
});
|
||||
try{
|
||||
readChunk(stream, true, in -> {
|
||||
byte version = in.readByte();
|
||||
tile.entity.read(in, version);
|
||||
});
|
||||
}catch(Exception e){
|
||||
throw new IOException("Failed to read tile entity of block: " + block, e);
|
||||
}
|
||||
}else{
|
||||
int consecutives = stream.readUnsignedByte();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.arc.collection.StringMap;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.graphics.Texture;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.game.DefaultWaves;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.io.JsonIO;
|
||||
|
||||
@@ -57,7 +58,9 @@ public class Map implements Comparable<Map>{
|
||||
|
||||
/** This creates a new instance.*/
|
||||
public Rules rules(){
|
||||
return JsonIO.read(Rules.class, tags.get("rules", "{}"));
|
||||
Rules result = JsonIO.read(Rules.class, tags.get("rules", "{}"));
|
||||
if(result.spawns.isEmpty()) result.spawns = DefaultWaves.get();
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Whether this map has a core of the enemy 'wave' team. Default: true.
|
||||
|
||||
@@ -3,12 +3,13 @@ package io.anuke.mindustry.maps;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.function.ExceptionRunnable;
|
||||
import io.anuke.arc.graphics.Texture;
|
||||
import io.anuke.arc.util.Disposable;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.serialization.Json;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.io.LegacyMapIO;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
@@ -17,7 +18,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Maps implements Disposable{
|
||||
/** List of all built-in maps. Filenames only. */
|
||||
private static final String[] defaultMapNames = {"fortress"};
|
||||
private static final String[] defaultMapNames = {"fortress", "shoreline", "labyrinth", "islands"};
|
||||
/** All maps stored in an ordered array. */
|
||||
private Array<Map> maps = new Array<>();
|
||||
/** Serializer for meta. */
|
||||
@@ -116,6 +117,14 @@ public class Maps implements Disposable{
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a legacy map by converting it to a non-legacy map and pasting it in a temp directory.
|
||||
* Should be followed up by {@link #importMap(FileHandle)} .*/
|
||||
public Map makeLegacyMap(FileHandle file) throws IOException{
|
||||
FileHandle dst = tmpDirectory.child("conversion_map." + mapExtension);
|
||||
LegacyMapIO.convertMap(file, dst);
|
||||
return MapIO.createMap(dst, true);
|
||||
}
|
||||
|
||||
/** Import a map, then save it. This updates all values and stored data necessary. */
|
||||
public void importMap(FileHandle file) throws IOException{
|
||||
FileHandle dest = findFile();
|
||||
@@ -124,6 +133,24 @@ public class Maps implements Disposable{
|
||||
loadMap(dest, true);
|
||||
}
|
||||
|
||||
/** Attempts to run the following code;
|
||||
* catches any errors and attempts to display them in a readable way.*/
|
||||
public void tryCatchMapError(ExceptionRunnable run){
|
||||
try{
|
||||
run.run();
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
|
||||
if("Outdated legacy map format".equals(e.getMessage())){
|
||||
ui.showError("$editor.errorlegacy");
|
||||
}else if(e.getMessage() != null && e.getMessage().contains("Incorrect header!")){
|
||||
ui.showError("$editor.errorheader");
|
||||
}else{
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a map completely. */
|
||||
public void removeMap(Map map){
|
||||
if(map.texture != null){
|
||||
|
||||
@@ -6,8 +6,7 @@ import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.BiConsumer;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.net.HttpRequestBuilder;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
@@ -67,7 +66,7 @@ public class Net{
|
||||
}else if(error.equals("alreadyconnected")){
|
||||
error = Core.bundle.get("error.alreadyconnected");
|
||||
}else if(!error.isEmpty()){
|
||||
error = Core.bundle.get("error.any") + "\n" + t.getClass().getSimpleName() + "\n" + (t.getMessage() == null ? "" : t.getMessage());
|
||||
error = Core.bundle.get("error.any") + "\n" + Strings.parseException(e, true);
|
||||
}
|
||||
|
||||
ui.showText("", Core.bundle.format("connectfail", error));
|
||||
|
||||
@@ -6,6 +6,8 @@ import io.anuke.mindustry.type.ItemStack;
|
||||
|
||||
/** An item image with text. */
|
||||
public class ItemDisplay extends Table{
|
||||
public final Item item;
|
||||
public final int amount;
|
||||
|
||||
public ItemDisplay(Item item){
|
||||
this(item, 0);
|
||||
@@ -14,5 +16,8 @@ public class ItemDisplay extends Table{
|
||||
public ItemDisplay(Item item, int amount){
|
||||
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4);
|
||||
add(item.localizedName()).padLeft(4);
|
||||
|
||||
this.item = item;
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,15 @@ import io.anuke.mindustry.world.meta.StatUnit;
|
||||
|
||||
/** An ItemDisplay, but for liquids. */
|
||||
public class LiquidDisplay extends Table{
|
||||
public final Liquid liquid;
|
||||
public final float amount;
|
||||
public final boolean perSecond;
|
||||
|
||||
public LiquidDisplay(Liquid liquid, float amount, boolean perSecond){
|
||||
this.liquid = liquid;
|
||||
this.amount = amount;
|
||||
this.perSecond = perSecond;
|
||||
|
||||
add(new Stack(){{
|
||||
add(new Image(liquid.getContentIcon()));
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ import io.anuke.mindustry.ui.BorderImage;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class CustomGameDialog extends FloatingDialog{
|
||||
public class
|
||||
CustomGameDialog extends FloatingDialog{
|
||||
private MapPlayDialog dialog = new MapPlayDialog();
|
||||
|
||||
public CustomGameDialog(){
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -29,12 +30,26 @@ public class FileChooser extends FloatingDialog{
|
||||
private Predicate<FileHandle> filter;
|
||||
private Consumer<FileHandle> selectListener;
|
||||
private boolean open;
|
||||
private int lastWidth = Core.graphics.getWidth(), lastHeight = Core.graphics.getHeight();
|
||||
|
||||
public static final Predicate<String> pngFiles = str -> str.equals("png");
|
||||
public static final Predicate<String> anyMapFiles = str -> str.equals(Vars.oldMapExtension) || str.equals(Vars.mapExtension);
|
||||
public static final Predicate<String> mapFiles = str -> str.equals(Vars.mapExtension);
|
||||
public static final Predicate<String> saveFiles = str -> str.equals(Vars.saveExtension);
|
||||
|
||||
public FileChooser(String title, Predicate<FileHandle> filter, boolean open, Consumer<FileHandle> result){
|
||||
super(title);
|
||||
this.open = open;
|
||||
this.filter = filter;
|
||||
this.selectListener = result;
|
||||
|
||||
update(() -> {
|
||||
if(Core.graphics.getWidth() != lastWidth || Core.graphics.getHeight() != lastHeight){
|
||||
updateFiles(false);
|
||||
lastHeight = Core.graphics.getHeight();
|
||||
lastWidth = Core.graphics.getWidth();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupWidgets(){
|
||||
@@ -268,14 +283,6 @@ public class FileChooser extends FloatingDialog{
|
||||
return this;
|
||||
}
|
||||
|
||||
public void fileSelected(Consumer<FileHandle> listener){
|
||||
this.selectListener = listener;
|
||||
}
|
||||
|
||||
public interface FileHandleFilter{
|
||||
boolean accept(FileHandle file);
|
||||
}
|
||||
|
||||
public class FileHistory{
|
||||
private Array<FileHandle> history = new Array<>();
|
||||
private int index;
|
||||
|
||||
@@ -56,7 +56,7 @@ public class HostDialog extends FloatingDialog{
|
||||
Net.host(Vars.port);
|
||||
player.isAdmin = true;
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true)));
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
hide();
|
||||
|
||||
@@ -90,16 +90,16 @@ public class LoadDialog extends FloatingDialog{
|
||||
slot.exportFile(file);
|
||||
setup();
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, true)));
|
||||
}
|
||||
}, false, saveExtension);
|
||||
}, false, FileChooser.saveFiles);
|
||||
}else{
|
||||
try{
|
||||
FileHandle file = Core.files.local("save-" + slot.getName() + "." + Vars.saveExtension);
|
||||
slot.exportFile(file);
|
||||
Platform.instance.shareFile(file);
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, true)));
|
||||
}
|
||||
}
|
||||
}).size(14 * 3).right();
|
||||
@@ -155,12 +155,12 @@ public class LoadDialog extends FloatingDialog{
|
||||
setup();
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
ui.showError(Core.bundle.format("save.import.fail", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("save.import.fail", Strings.parseException(e, true)));
|
||||
}
|
||||
}else{
|
||||
ui.showError("$save.import.invalid");
|
||||
}
|
||||
}, true, saveExtension);
|
||||
}, true, FileChooser.saveFiles);
|
||||
}).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public class MapPlayDialog extends FloatingDialog{
|
||||
Difficulty difficulty = Difficulty.normal;
|
||||
CustomRulesDialog dialog = new CustomRulesDialog();
|
||||
Rules rules;
|
||||
Gamemode selectedGamemode;
|
||||
Gamemode selectedGamemode = Gamemode.survival;
|
||||
|
||||
public MapPlayDialog(){
|
||||
super("");
|
||||
@@ -28,6 +28,8 @@ public class MapPlayDialog extends FloatingDialog{
|
||||
cont.clearChildren();
|
||||
rules = map.rules();
|
||||
|
||||
rules = selectedGamemode.apply(map.rules());
|
||||
|
||||
Table selmode = new Table();
|
||||
selmode.add("$level.mode").colspan(4);
|
||||
selmode.row();
|
||||
@@ -43,8 +45,8 @@ public class MapPlayDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
modes.addButton(mode.toString(), "toggle", () -> {
|
||||
selectedGamemode = selectedGamemode == mode ? null : mode;
|
||||
rules = selectedGamemode == null ? map.rules() : mode.apply(map.rules());
|
||||
selectedGamemode = mode;
|
||||
rules = mode.apply(map.rules());
|
||||
}).update(b -> b.setChecked(selectedGamemode == mode)).size(140f, 54f);
|
||||
if(i++ % 2 == 1) modes.row();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.Scaling;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
@@ -23,8 +23,19 @@ public class MapsDialog extends FloatingDialog{
|
||||
addCloseButton();
|
||||
buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> {
|
||||
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
|
||||
try{
|
||||
Map map = MapIO.createMap(file, true);
|
||||
world.maps.tryCatchMapError(() -> {
|
||||
if(MapIO.isImage(file)){
|
||||
ui.showError("$editor.errorimage");
|
||||
return;
|
||||
}
|
||||
|
||||
Map map;
|
||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||
map = MapIO.createMap(file, true);
|
||||
}else{
|
||||
map = world.maps.makeLegacyMap(file);
|
||||
}
|
||||
|
||||
String name = map.tags.get("name");
|
||||
if(name == null){
|
||||
ui.showError("$editor.errorname");
|
||||
@@ -34,27 +45,21 @@ public class MapsDialog extends FloatingDialog{
|
||||
Map conflict = world.maps.all().find(m -> m.name().equals(name));
|
||||
|
||||
if(conflict != null && !conflict.custom){
|
||||
ui.showError(Core.bundle.format("editor.import.exists", name));
|
||||
ui.showInfo(Core.bundle.format("editor.import.exists", name));
|
||||
}else if(conflict != null){
|
||||
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
||||
try{
|
||||
world.maps.tryCatchMapError(() -> {
|
||||
world.maps.importMap(file);
|
||||
setup();
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}else{
|
||||
world.maps.importMap(file);
|
||||
world.maps.importMap(map.file);
|
||||
setup();
|
||||
}
|
||||
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
}, true, mapExtension);
|
||||
});
|
||||
}, true, FileChooser.anyMapFiles);
|
||||
}).size(230f, 64f);
|
||||
|
||||
shown(this::setup);
|
||||
|
||||
@@ -178,7 +178,6 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Core.bundle.get("setting.fpscap.none") : Core.bundle.format("setting.fpscap.text", s)));
|
||||
graphics.sliderPref("chatopacity", 100, 0, 100, 5, s -> s + "%");
|
||||
|
||||
|
||||
if(!mobile){
|
||||
graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b));
|
||||
graphics.checkPref("fullscreen", false, b -> {
|
||||
@@ -221,6 +220,22 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
graphics.checkPref("animatedshields", !mobile);
|
||||
graphics.checkPref("lasers", true);
|
||||
graphics.checkPref("pixelate", false);
|
||||
|
||||
//TODO is this necessary?
|
||||
/*
|
||||
graphics.checkPref("linear", false, b -> {
|
||||
for(Texture tex : Core.atlas.getTextures()){
|
||||
TextureFilter filter = b ? TextureFilter.Linear : TextureFilter.Nearest;
|
||||
tex.setFilter(filter, filter);
|
||||
}
|
||||
});
|
||||
|
||||
if(Core.settings.getBool("linear")){
|
||||
for(Texture tex : Core.atlas.getTextures()){
|
||||
TextureFilter filter = TextureFilter.Linear;
|
||||
tex.setFilter(filter, filter);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void back(){
|
||||
|
||||
@@ -73,8 +73,6 @@ public class Block extends BlockStorage{
|
||||
public Layer layer2 = null;
|
||||
/** whether this block can be replaced in all cases */
|
||||
public boolean alwaysReplace = false;
|
||||
/** whether this block has instant transfer checking. used for calculations to prevent infinite loops. */
|
||||
public boolean instantTransfer = false;
|
||||
/** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */
|
||||
public BlockGroup group = BlockGroup.none;
|
||||
/** List of block flags. Used for AI indexing. */
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.anuke.mindustry.world;
|
||||
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.world.modules.*;
|
||||
@@ -10,7 +9,6 @@ import io.anuke.mindustry.world.modules.*;
|
||||
* Prevents garbage when loading previews.
|
||||
*/
|
||||
public class CachedTile extends Tile{
|
||||
private static IntMap<TileEntity> entities = new IntMap<>();
|
||||
|
||||
public CachedTile(){
|
||||
super(0, 0);
|
||||
@@ -23,7 +21,8 @@ public class CachedTile extends Tile{
|
||||
|
||||
@Override
|
||||
protected void preChanged(){
|
||||
super.setTeam(Team.none);
|
||||
//this basically overrides the old tile code and doesn't remove from proximity
|
||||
team = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,19 +32,14 @@ public class CachedTile extends Tile{
|
||||
Block block = block();
|
||||
|
||||
if(block.hasEntity()){
|
||||
//cache all entity types so only one is ever created per block type. do not add it.
|
||||
if(!entities.containsKey(block.id)){
|
||||
TileEntity n = block.newEntity();
|
||||
n.cons = new ConsumeModule(entity);
|
||||
n.tile = this;
|
||||
if(block.hasItems) n.items = new ItemModule();
|
||||
if(block.hasLiquids) n.liquids = new LiquidModule();
|
||||
if(block.hasPower) n.power = new PowerModule();
|
||||
entities.put(block.id, n);
|
||||
}
|
||||
|
||||
entity = entities.get(block.id);
|
||||
|
||||
TileEntity n = block.newEntity();
|
||||
n.cons = new ConsumeModule(entity);
|
||||
n.tile = this;
|
||||
n.block = block;
|
||||
if(block.hasItems) n.items = new ItemModule();
|
||||
if(block.hasLiquids) n.liquids = new LiquidModule();
|
||||
if(block.hasPower) n.power = new PowerModule();
|
||||
entity = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
core/src/io/anuke/mindustry/world/DirectionalItemBuffer.java
Normal file
77
core/src/io/anuke/mindustry/world/DirectionalItemBuffer.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package io.anuke.mindustry.world;
|
||||
|
||||
import io.anuke.annotations.Annotations.Struct;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.gen.BufferItem;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class DirectionalItemBuffer{
|
||||
public final long[][] buffers;
|
||||
public final int[] indexes;
|
||||
private final float speed;
|
||||
|
||||
public DirectionalItemBuffer(int capacity, float speed){
|
||||
this.buffers = new long[4][capacity];
|
||||
this.indexes = new int[5];
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public boolean accepts(int buffer){
|
||||
return indexes[buffer] < buffers[buffer].length;
|
||||
}
|
||||
|
||||
public void accept(int buffer, Item item){
|
||||
if(!accepts(buffer)) return;
|
||||
buffers[buffer][indexes[buffer]++] = BufferItem.get((byte)item.id, Time.time());
|
||||
}
|
||||
|
||||
public Item poll(int buffer){
|
||||
if(indexes[buffer] > 0){
|
||||
long l = buffers[buffer][0];
|
||||
float time = BufferItem.time(l);
|
||||
|
||||
if(Time.time() >= time + speed || Time.time() < time){
|
||||
return content.item(BufferItem.item(l));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void remove(int buffer){
|
||||
System.arraycopy(buffers[buffer], 1, buffers[buffer], 0, indexes[buffer] - 1);
|
||||
indexes[buffer] --;
|
||||
}
|
||||
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
for(int i = 0; i < 4; i++){
|
||||
stream.writeByte(indexes[i]);
|
||||
stream.writeByte(buffers[i].length);
|
||||
for(long l : buffers[i]){
|
||||
stream.writeLong(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void read(DataInput stream) throws IOException{
|
||||
for(int i = 0; i < 4; i++){
|
||||
indexes[i] = stream.readByte();
|
||||
byte length = stream.readByte();
|
||||
for(int j = 0; j < length; j++){
|
||||
long value = stream.readLong();
|
||||
if(j < buffers[i].length){
|
||||
buffers[i][j] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Struct
|
||||
class BufferItemStruct{
|
||||
byte item;
|
||||
float time;
|
||||
}
|
||||
}
|
||||
@@ -439,6 +439,6 @@ public class Tile implements Position, TargetTrait{
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return floor.name + ":" + block.name + ":" + content.block(overlay) + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass()));
|
||||
return floor.name + ":" + block.name + ":" + content.block(overlay) + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) + ":" + getTeam();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.world.blocks;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
@@ -56,6 +57,7 @@ public class Floor extends Block{
|
||||
protected byte eq = 0;
|
||||
protected Array<Block> blenders = new Array<>();
|
||||
protected IntSet blended = new IntSet();
|
||||
protected TextureRegion edgeRegion, edgierRegion;
|
||||
|
||||
public Floor(String name){
|
||||
super(name);
|
||||
@@ -82,6 +84,8 @@ public class Floor extends Block{
|
||||
edges = Core.atlas.find(name + "-edge").split(size, size);
|
||||
}
|
||||
region = variantRegions[0];
|
||||
edgeRegion = Core.atlas.find("edge");
|
||||
edgierRegion = Core.atlas.find("edgier");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,14 +144,32 @@ public class Floor extends Block{
|
||||
Point2 point = Geometry.d8[i];
|
||||
Tile other = tile.getNearby(point);
|
||||
if(other != null && other.floor() == block){
|
||||
TextureRegion region = edge((Floor)block, type(i), 2 - (point.x + 1), 2 - (point.y + 1));
|
||||
TextureRegion region = edge((Floor)block, 2 - (point.x + 1), 2 - (point.y + 1));
|
||||
Draw.rect(region, tile.worldx(), tile.worldy());
|
||||
|
||||
if(!sameLayer && block.cacheLayer.ordinal() > cacheLayer.ordinal()){
|
||||
Draw.rect(block.variantRegions()[0], tile.worldx() + point.x*tilesize, tile.worldy() + point.y*tilesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//'new' style of edges with shadows instead of colors, not used currently
|
||||
protected void drawEdgesFlat(Tile tile, boolean sameLayer){
|
||||
for(int i = 0; i < 4; i++){
|
||||
Tile other = tile.getNearby(i);
|
||||
if(other != null && doEdge(other.floor(), sameLayer)){
|
||||
Color color = other.floor().color;
|
||||
Draw.color(color.r, color.g, color.b, 1f);
|
||||
Draw.rect(edgeRegion, tile.worldx(), tile.worldy(), i*90);
|
||||
}
|
||||
}
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
|
||||
protected TextureRegion[][] edges(){
|
||||
return ((Floor)blendGroup).edges;
|
||||
}
|
||||
@@ -160,28 +182,12 @@ public class Floor extends Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
int type(int i){
|
||||
if(!eq(i - 1) && !eq(i + 1)){
|
||||
//case 0: touching
|
||||
return 0;
|
||||
}else if(eq(i - 1) && eq(i - 2) && eq(i + 1) && eq(i + 2)){
|
||||
//case 2: surrounded
|
||||
return 2;
|
||||
}else if(eq(i - 1) && eq(i + 1)){
|
||||
//case 1: flat
|
||||
return 1;
|
||||
}else{
|
||||
//case 0 is rounded, so it's the safest choice, should work for most possibilities
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
boolean eq(int i){
|
||||
return (eq & (1 << Mathf.mod(i, 8))) != 0;
|
||||
}
|
||||
|
||||
TextureRegion edge(Floor block, int type, int x, int y){
|
||||
return block.edges()[x + type * 3][2 - y];
|
||||
TextureRegion edge(Floor block, int x, int y){
|
||||
return block.edges()[x][2 - y];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,8 @@ import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Door extends Wall{
|
||||
protected final Rectangle rect = new Rectangle();
|
||||
|
||||
@@ -68,6 +70,7 @@ public class Door extends Wall{
|
||||
}
|
||||
|
||||
entity.open = !entity.open;
|
||||
world.pathfinder.updateSolid(tile);
|
||||
if(!entity.open){
|
||||
Effects.effect(closefx, tile.drawx(), tile.drawy());
|
||||
}else{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.gen.BufferItem;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.meta.BlockGroup;
|
||||
|
||||
import java.io.*;
|
||||
@@ -19,7 +19,6 @@ public class Junction extends Block{
|
||||
super(name);
|
||||
update = true;
|
||||
solid = true;
|
||||
instantTransfer = true;
|
||||
group = BlockGroup.transportation;
|
||||
}
|
||||
|
||||
@@ -31,18 +30,17 @@ public class Junction extends Block{
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
JunctionEntity entity = tile.entity();
|
||||
DirectionalItemBuffer buffer = entity.buffer;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
Buffer buffer = entity.buffers[i];
|
||||
|
||||
if(buffer.index > 0){
|
||||
if(buffer.index > buffer.items.length) buffer.index = buffer.items.length;
|
||||
long l = buffer.items[0];
|
||||
float time = Float.intBitsToFloat(Pack.leftInt(l));
|
||||
if(buffer.indexes[i] > 0){
|
||||
if(buffer.indexes[i] > capacity) buffer.indexes[i] = capacity;
|
||||
long l = buffer.buffers[i][0];
|
||||
float time = BufferItem.time(l);
|
||||
|
||||
if(Time.time() >= time + speed || Time.time() < time){
|
||||
|
||||
Item item = content.item(Pack.rightInt(l));
|
||||
Item item = content.item(BufferItem.item(l));
|
||||
Tile dest = tile.getNearby(i);
|
||||
|
||||
//skip blocks that don't want the item, keep waiting until they do
|
||||
@@ -51,8 +49,8 @@ public class Junction extends Block{
|
||||
}
|
||||
|
||||
dest.block().handleItem(item, dest, tile);
|
||||
System.arraycopy(buffer.items, 1, buffer.items, 0, buffer.index - 1);
|
||||
buffer.index--;
|
||||
System.arraycopy(buffer.buffers[i], 1, buffer.buffers[i], 0, buffer.indexes[i] - 1);
|
||||
buffer.indexes[i] --;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,9 +59,8 @@ public class Junction extends Block{
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
JunctionEntity entity = tile.entity();
|
||||
long value = Pack.longInt(Float.floatToIntBits(Time.time()), item.id);
|
||||
int relative = source.relativeTo(tile.x, tile.y);
|
||||
entity.buffers[relative].add(value);
|
||||
entity.buffer.accept(relative, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,7 +68,7 @@ public class Junction extends Block{
|
||||
JunctionEntity entity = tile.entity();
|
||||
int relative = source.relativeTo(tile.x, tile.y);
|
||||
|
||||
if(entity == null || relative == -1 || entity.buffers[relative].full())
|
||||
if(entity == null || relative == -1 || !entity.buffer.accepts(relative))
|
||||
return false;
|
||||
Tile to = tile.getNearby(relative);
|
||||
return to != null && to.link().entity != null;
|
||||
@@ -83,55 +80,18 @@ public class Junction extends Block{
|
||||
}
|
||||
|
||||
class JunctionEntity extends TileEntity{
|
||||
Buffer[] buffers = {new Buffer(), new Buffer(), new Buffer(), new Buffer()};
|
||||
DirectionalItemBuffer buffer = new DirectionalItemBuffer(capacity, speed);
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
for(Buffer b : buffers){
|
||||
b.write(stream);
|
||||
}
|
||||
buffer.write(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput stream, byte revision) throws IOException{
|
||||
super.read(stream, revision);
|
||||
for(Buffer b : buffers){
|
||||
b.read(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Buffer{
|
||||
long[] items = new long[capacity];
|
||||
int index;
|
||||
|
||||
void add(long id){
|
||||
if(full()) return;
|
||||
items[index++] = id;
|
||||
}
|
||||
|
||||
boolean full(){
|
||||
return index >= items.length - 1;
|
||||
}
|
||||
|
||||
void write(DataOutput stream) throws IOException{
|
||||
stream.writeByte((byte)index);
|
||||
stream.writeByte((byte)items.length);
|
||||
for(long l : items){
|
||||
stream.writeLong(l);
|
||||
}
|
||||
}
|
||||
|
||||
void read(DataInput stream) throws IOException{
|
||||
index = stream.readByte();
|
||||
byte length = stream.readByte();
|
||||
for(int i = 0; i < length; i++){
|
||||
long l = stream.readLong();
|
||||
if(i < items.length){
|
||||
items[i] = l;
|
||||
}
|
||||
}
|
||||
buffer.read(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class MassDriver extends Block{
|
||||
|
||||
//reload regardless of state
|
||||
if(entity.reload > 0f){
|
||||
entity.reload = Mathf.clamp(entity.reload - entity.delta() / reloadTime);
|
||||
entity.reload = Mathf.clamp(entity.reload - entity.delta() / reloadTime * entity.power.satisfaction);
|
||||
}
|
||||
|
||||
//cleanup waiting shooters that are not valid
|
||||
@@ -114,7 +114,7 @@ public class MassDriver extends Block{
|
||||
}
|
||||
|
||||
//align to shooter rotation
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(entity.currentShooter()), rotateSpeed);
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(entity.currentShooter()), rotateSpeed * entity.power.satisfaction);
|
||||
}else if(entity.state == DriverState.shooting){
|
||||
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
|
||||
if(!hasLink || !entity.waitingShooters.isEmpty()){
|
||||
@@ -133,7 +133,7 @@ public class MassDriver extends Block{
|
||||
other.waitingShooters.add(tile);
|
||||
|
||||
//align to target location
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed);
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed * entity.power.satisfaction);
|
||||
|
||||
//fire when it's the first in the queue and angles are ready.
|
||||
if(other.currentShooter() == tile &&
|
||||
@@ -214,7 +214,8 @@ public class MassDriver extends Block{
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
return tile.entity.items.total() < itemCapacity;
|
||||
//mass drivers that ouput only cannot accept items
|
||||
return tile.entity.items.total() < itemCapacity && linkValid(tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,41 +1,56 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Edges;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.meta.BlockGroup;
|
||||
|
||||
public class OverflowGate extends Router{
|
||||
import java.io.*;
|
||||
|
||||
public class OverflowGate extends Block{
|
||||
protected int bufferCapacity = 10;
|
||||
protected float speed = 45f;
|
||||
|
||||
public OverflowGate(String name){
|
||||
super(name);
|
||||
hasItems = true;
|
||||
speed = 1f;
|
||||
solid = true;
|
||||
update = true;
|
||||
group = BlockGroup.transportation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
SplitterEntity entity = tile.entity();
|
||||
OverflowGateEntity entity = tile.entity();
|
||||
|
||||
if(entity.lastItem == null && entity.items.total() > 0){
|
||||
entity.items.clear();
|
||||
}
|
||||
|
||||
if(entity.lastItem != null){
|
||||
entity.time += 1f / speed * Time.delta();
|
||||
Tile target = getTileTarget(tile, entity.lastItem, entity.lastInput, false);
|
||||
|
||||
if(target != null && (entity.time >= 1f)){
|
||||
getTileTarget(tile, entity.lastItem, entity.lastInput, true);
|
||||
target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target));
|
||||
entity.items.remove(entity.lastItem, 1);
|
||||
entity.lastItem = null;
|
||||
for(int i = 0; i < 4; i++){
|
||||
Item item = entity.buffer.poll(i);
|
||||
if(item != null){
|
||||
Tile other = getTileTarget(tile, item, tile.getNearby(i), true);
|
||||
if(other != null && other.block().acceptItem(item, other, tile)){
|
||||
other.block().handleItem(item, other, tile);
|
||||
entity.buffer.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
OverflowGateEntity entity = tile.entity();
|
||||
return entity.buffer.accepts(tile.relativeTo(source.x, source.y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
OverflowGateEntity entity = tile.entity();
|
||||
int buffer = tile.relativeTo(source.x, source.y);
|
||||
if(entity.buffer.accepts(buffer)){
|
||||
entity.buffer.accept(buffer, item);
|
||||
}
|
||||
}
|
||||
|
||||
Tile getTileTarget(Tile tile, Item item, Tile src, boolean flip){
|
||||
int from = tile.relativeTo(src.x, src.y);
|
||||
if(from == -1) return null;
|
||||
@@ -70,4 +85,32 @@ public class OverflowGate extends Router{
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new OverflowGateEntity();
|
||||
}
|
||||
|
||||
public class OverflowGateEntity extends TileEntity{
|
||||
DirectionalItemBuffer buffer = new DirectionalItemBuffer(bufferCapacity, speed);
|
||||
|
||||
@Override
|
||||
public byte version(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
buffer.write(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput stream, byte revision) throws IOException{
|
||||
super.read(stream, revision);
|
||||
if(revision == 1){
|
||||
buffer.read(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public class Router extends Block{
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
SplitterEntity entity = tile.entity();
|
||||
RouterEntity entity = tile.entity();
|
||||
|
||||
if(entity.lastItem == null && entity.items.total() > 0){
|
||||
entity.items.clear();
|
||||
@@ -42,14 +42,14 @@ public class Router extends Block{
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
SplitterEntity entity = tile.entity();
|
||||
RouterEntity entity = tile.entity();
|
||||
|
||||
return tile.getTeam() == source.getTeam() && entity.lastItem == null && entity.items.total() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
SplitterEntity entity = tile.entity();
|
||||
RouterEntity entity = tile.entity();
|
||||
entity.items.add(item, 1);
|
||||
entity.lastItem = item;
|
||||
entity.time = 0f;
|
||||
@@ -72,7 +72,7 @@ public class Router extends Block{
|
||||
|
||||
@Override
|
||||
public int removeStack(Tile tile, Item item, int amount){
|
||||
SplitterEntity entity = tile.entity();
|
||||
RouterEntity entity = tile.entity();
|
||||
int result = super.removeStack(tile, item, amount);
|
||||
if(result != 0 && item == entity.lastItem){
|
||||
entity.lastItem = null;
|
||||
@@ -82,10 +82,10 @@ public class Router extends Block{
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new SplitterEntity();
|
||||
return new RouterEntity();
|
||||
}
|
||||
|
||||
public class SplitterEntity extends TileEntity{
|
||||
public class RouterEntity extends TileEntity{
|
||||
Item lastItem;
|
||||
Tile lastInput;
|
||||
float time;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
@@ -10,8 +9,7 @@ import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.ItemSelection;
|
||||
import io.anuke.mindustry.world.meta.BlockGroup;
|
||||
|
||||
@@ -22,11 +20,13 @@ import static io.anuke.mindustry.Vars.content;
|
||||
public class Sorter extends Block{
|
||||
private static Item lastItem;
|
||||
|
||||
protected int bufferCapacity = 20;
|
||||
protected float speed = 45f;
|
||||
|
||||
public Sorter(String name){
|
||||
super(name);
|
||||
update = true;
|
||||
solid = true;
|
||||
instantTransfer = true;
|
||||
group = BlockGroup.transportation;
|
||||
configurable = true;
|
||||
}
|
||||
@@ -57,24 +57,42 @@ public class Sorter extends Block{
|
||||
if(entity.sortItem == null) return;
|
||||
|
||||
Draw.color(entity.sortItem.color);
|
||||
Draw.rect("blank", tile.worldx(), tile.worldy(), 4f, 4f);
|
||||
Draw.rect("center", tile.worldx(), tile.worldy());
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
Tile to = getTileTarget(item, tile, source, false);
|
||||
public void update(Tile tile){
|
||||
SorterEntity entity = tile.entity();
|
||||
|
||||
return to != null && to.block().acceptItem(item, to, tile);
|
||||
for(int i = 0; i < 4; i++){
|
||||
Item item = entity.buffer.poll(i);
|
||||
if(item != null){
|
||||
Tile other = getTileTarget(item, tile, tile.getNearby(i), true);
|
||||
if(other != null && other.block().acceptItem(item, other, tile)){
|
||||
other.block().handleItem(item, other, tile);
|
||||
entity.buffer.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
SorterEntity entity = tile.entity();
|
||||
return entity.buffer.accepts(tile.relativeTo(source.x, source.y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
Tile to = getTileTarget(item, tile, source, true);
|
||||
|
||||
to.block().handleItem(item, to, tile);
|
||||
SorterEntity entity = tile.entity();
|
||||
int buffer = tile.relativeTo(source.x, source.y);
|
||||
if(entity.buffer.accepts(buffer)){
|
||||
entity.buffer.accept(buffer, item);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){
|
||||
SorterEntity entity = dest.entity();
|
||||
|
||||
@@ -87,10 +105,8 @@ public class Sorter extends Block{
|
||||
}else{
|
||||
Tile a = dest.getNearby(Mathf.mod(dir - 1, 4));
|
||||
Tile b = dest.getNearby(Mathf.mod(dir + 1, 4));
|
||||
boolean ac = a != null && !(a.block().instantTransfer && source.block().instantTransfer) &&
|
||||
a.block().acceptItem(item, a, dest);
|
||||
boolean bc = b != null && !(b.block().instantTransfer && source.block().instantTransfer) &&
|
||||
b.block().acceptItem(item, b, dest);
|
||||
boolean ac = a != null && a.block().acceptItem(item, a, dest);
|
||||
boolean bc = b != null && b.block().acceptItem(item, b, dest);
|
||||
|
||||
if(ac && !bc){
|
||||
to = a;
|
||||
@@ -101,12 +117,10 @@ public class Sorter extends Block{
|
||||
}else{
|
||||
if(dest.rotation() == 0){
|
||||
to = a;
|
||||
if(flip)
|
||||
dest.rotation((byte)1);
|
||||
if(flip) dest.rotation((byte)1);
|
||||
}else{
|
||||
to = b;
|
||||
if(flip)
|
||||
dest.rotation((byte)0);
|
||||
if(flip) dest.rotation((byte)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,19 +142,29 @@ public class Sorter extends Block{
|
||||
return new SorterEntity();
|
||||
}
|
||||
|
||||
public static class SorterEntity extends TileEntity{
|
||||
public Item sortItem;
|
||||
public class SorterEntity extends TileEntity{
|
||||
DirectionalItemBuffer buffer = new DirectionalItemBuffer(bufferCapacity, speed);
|
||||
Item sortItem;
|
||||
|
||||
@Override
|
||||
public byte version(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
stream.writeShort(sortItem == null ? -1 : sortItem.id);
|
||||
buffer.write(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput stream, byte revision) throws IOException{
|
||||
super.read(stream, revision);
|
||||
sortItem = content.item(stream.readShort());
|
||||
if(revision == 1){
|
||||
buffer.read(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,46 @@
|
||||
package io.anuke.mindustry.world.blocks.sandbox;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.distribution.Sorter;
|
||||
import io.anuke.mindustry.world.blocks.ItemSelection;
|
||||
import io.anuke.mindustry.world.meta.BlockGroup;
|
||||
|
||||
public class ItemSource extends Sorter{
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class ItemSource extends Block{
|
||||
private static Item lastItem;
|
||||
|
||||
public ItemSource(String name){
|
||||
super(name);
|
||||
hasItems = true;
|
||||
update = true;
|
||||
solid = true;
|
||||
group = BlockGroup.transportation;
|
||||
configurable = true;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
public static void setItemSourceItem(Player player, Tile tile, Item item){
|
||||
ItemSourceEntity entity = tile.entity();
|
||||
if(entity != null){
|
||||
entity.outputItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerPlaced(Tile tile){
|
||||
Core.app.post(() -> Call.setItemSourceItem(null, tile, lastItem));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,17 +55,59 @@ public class ItemSource extends Sorter{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
SorterEntity entity = tile.entity();
|
||||
if(entity.sortItem == null) return;
|
||||
public void draw(Tile tile){
|
||||
super.draw(tile);
|
||||
|
||||
entity.items.set(entity.sortItem, 1);
|
||||
tryDump(tile, entity.sortItem);
|
||||
entity.items.set(entity.sortItem, 0);
|
||||
ItemSourceEntity entity = tile.entity();
|
||||
if(entity.outputItem == null) return;
|
||||
|
||||
Draw.color(entity.outputItem.color);
|
||||
Draw.rect("center", tile.worldx(), tile.worldy());
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
ItemSourceEntity entity = tile.entity();
|
||||
if(entity.outputItem == null) return;
|
||||
|
||||
entity.items.set(entity.outputItem, 1);
|
||||
tryDump(tile, entity.outputItem);
|
||||
entity.items.set(entity.outputItem, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTable(Tile tile, Table table){
|
||||
ItemSourceEntity entity = tile.entity();
|
||||
ItemSelection.buildItemTable(table, () -> entity.outputItem, item -> {
|
||||
lastItem = item;
|
||||
Call.setItemSourceItem(null, tile, item);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ItemSourceEntity();
|
||||
}
|
||||
|
||||
public class ItemSourceEntity extends TileEntity{
|
||||
Item outputItem;
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
stream.writeShort(outputItem == null ? -1 : outputItem.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput stream, byte revision) throws IOException{
|
||||
super.read(stream, revision);
|
||||
outputItem = content.item(stream.readShort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class LiquidSource extends Block{
|
||||
|
||||
if(entity.source != null){
|
||||
Draw.color(entity.source.color);
|
||||
Draw.rect("blank", tile.worldx(), tile.worldy(), 4f, 4f);
|
||||
Draw.rect("center", tile.worldx(), tile.worldy());
|
||||
Draw.color();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,8 @@ public class MechPad extends Block{
|
||||
|
||||
protected static boolean checkValidTap(Tile tile, Player player){
|
||||
MechFactoryEntity entity = tile.entity();
|
||||
return Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize / 2f &&
|
||||
Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize / 2f && entity.cons.valid() && entity.player == null;
|
||||
return Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize &&
|
||||
Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize && entity.cons.valid() && entity.player == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user