Merge branch 'master' of https://github.com/Anuken/Mindustry into rendering-optimizations

# Conflicts:
#	core/assets/sprites/sprites.atlas
#	core/assets/sprites/sprites.png
#	core/src/io/anuke/mindustry/core/Renderer.java
#	core/src/io/anuke/mindustry/entities/units/types/Drone.java
#	core/src/io/anuke/mindustry/graphics/CacheLayer.java
#	core/src/io/anuke/mindustry/world/blocks/Floor.java
This commit is contained in:
Anuken
2018-11-26 13:23:38 -05:00
109 changed files with 1495 additions and 1370 deletions

View File

@@ -33,6 +33,7 @@ public class Vars{
public static final String appName = "Mindustry";
public static final String discordURL = "https://discord.gg/mindustry";
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
public static final String contributorsURL = "https://api.github.com/repos/Anuken/Mindustry/contributors";
public static final String crashReportURL = "http://mindustry.us.to/report";
//time between waves in frames (on normal mode)
public static final float wavespace = 60 * 60 * 1.5f;
@@ -73,6 +74,7 @@ public class Vars{
};
//server port
public static final int port = 6567;
public static boolean disableUI;
public static boolean testMobile;
//shorthand for whether or not this is running on android or ios
public static boolean mobile;
@@ -80,6 +82,8 @@ public class Vars{
public static boolean android;
//main data directory
public static FileHandle dataDirectory;
//subdirectory for screenshots
public static FileHandle screenshotDirectory;
//directory for user-created map data
public static FileHandle customMapDirectory;
//save file directory
@@ -170,6 +174,7 @@ public class Vars{
android = Gdx.app.getType() == ApplicationType.Android;
dataDirectory = Settings.getDataDirectory(appName);
screenshotDirectory = dataDirectory.child("screenshots/");
customMapDirectory = dataDirectory.child("maps/");
saveDirectory = dataDirectory.child("saves/");
baseCameraScale = Math.round(Unit.dp.scl(4));

View File

@@ -21,7 +21,6 @@ import io.anuke.ucore.util.ThreadArray;
import static io.anuke.mindustry.Vars.*;
//TODO consider using quadtrees for finding specific types of blocks within an area
//TODO maybe use Arrays instead of ObjectSets?
/**Class used for indexing special target blocks for AI.*/
@SuppressWarnings("unchecked")

View File

@@ -182,7 +182,7 @@ public class Pathfinder{
}
}
state.spawner.checkAllQuadrants();
world.spawner.checkAllQuadrants();
}
class PathData{

View File

@@ -37,6 +37,7 @@ public class UnitTypes implements ContentList{
};
spirit = new UnitType("spirit", Spirit.class, Spirit::new){{
weapon = Weapons.healBlasterDrone;
isFlying = true;
drag = 0.01f;
speed = 0.2f;

View File

@@ -7,7 +7,7 @@ import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Weapon;
public class Weapons implements ContentList{
public static Weapon blaster, blasterSmall, glaiveBlaster, droneBlaster, healBlaster, chainBlaster, shockgun,
public static Weapon blaster, blasterSmall, glaiveBlaster, droneBlaster, healBlaster, healBlasterDrone, chainBlaster, shockgun,
sapper, swarmer, bomber, bomberTrident, flakgun, flamethrower, missiles, artillery, laserBurster;
@Override
@@ -169,6 +169,16 @@ public class Weapons implements ContentList{
ejectEffect = Fx.none;
ammo = AmmoTypes.lancerLaser;
}};
healBlasterDrone = new Weapon("heal-blaster"){{
length = 1.5f;
reload = 40f;
width = 0.5f;
roundrobin = true;
ejectEffect = Fx.none;
recoil = 2f;
ammo = AmmoTypes.healBlaster;
}};
}
@Override

View File

@@ -64,9 +64,9 @@ public class LiquidBlocks extends BlockList implements ContentList{
}};
phaseConduit = new LiquidBridge("phase-conduit"){{
range = 11;
range = 12;
hasPower = true;
consumes.power(0.05f);
consumes.power(0.03f);
}};
}
}

View File

@@ -32,24 +32,13 @@ public class TurretBlocks extends BlockList implements ContentList{
hail = new ArtilleryTurret("hail"){{
ammoTypes = new AmmoType[]{AmmoTypes.artilleryDense, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary};
reload = 70f;
reload = 60f;
recoil = 2f;
range = 230f;
inaccuracy = 1f;
shootCone = 10f;
health = 120;
}};
/*
scatter = new BurstTurret("scatter"){{
ammoTypes = new AmmoType[]{AmmoTypes.flakCopper};
reload = 70f;
recoil = 2f;
shots = 3;
range = 220f;
inaccuracy = 2f;
shootCone = 40f;
health = 120;
}};*/
scorch = new LiquidTurret("scorch"){
protected TextureRegion shootRegion;
@@ -117,11 +106,11 @@ public class TurretBlocks extends BlockList implements ContentList{
arc = new PowerTurret("arc"){{
shootType = AmmoTypes.arc;
reload = 55f;
reload = 85f;
shootShake = 1f;
shootCone = 40f;
rotatespeed = 8f;
powerUsed = 7f;
powerUsed = 10f;
powerCapacity = 30f;
range = 150f;
shootEffect = ShootFx.lightningShoot;
@@ -132,7 +121,7 @@ public class TurretBlocks extends BlockList implements ContentList{
swarmer = new BurstTurret("swarmer"){{
ammoTypes = new AmmoType[]{AmmoTypes.missileExplosive, AmmoTypes.missileIncindiary, AmmoTypes.missileSurge};
reload = 60f;
reload = 50f;
shots = 4;
burstSpacing = 5;
inaccuracy = 10f;
@@ -156,7 +145,7 @@ public class TurretBlocks extends BlockList implements ContentList{
size = 2;
range = 120f;
ammoTypes = new AmmoType[]{AmmoTypes.bulletCopper, AmmoTypes.bulletDense, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon};
reload = 40f;
reload = 35f;
restitution = 0.03f;
ammoEjectBack = 3f;
cooldown = 0.03f;
@@ -216,7 +205,6 @@ public class TurretBlocks extends BlockList implements ContentList{
}};
fuse = new ItemTurret("fuse"){{
//TODO make it use power
ammoTypes = new AmmoType[]{AmmoTypes.fuseShotgun};
reload = 50f;
shootShake = 4f;

View File

@@ -43,7 +43,7 @@ public class TurretBullets extends BulletList implements ContentList{
};
healBullet = new BulletType(5.2f, 13){
float healAmount = 21f;
float healPercent = 3f;
{
hiteffect = BulletFx.hitLaser;
@@ -51,6 +51,11 @@ public class TurretBullets extends BulletList implements ContentList{
collidesTeam = true;
}
@Override
public boolean collides(Bullet b, Tile tile){
return tile.getTeam() != b.getTeam() || tile.entity.healthf() < 1f;
}
@Override
public void draw(Bullet b){
Draw.color(Palette.heal);
@@ -67,8 +72,8 @@ public class TurretBullets extends BulletList implements ContentList{
tile = tile.target();
if(tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
Effects.effect(BlockFx.healBlock, tile.drawx(), tile.drawy(), tile.block().size);
tile.entity.healBy(healAmount);
Effects.effect(BlockFx.healBlockFull, Palette.heal, tile.drawx(), tile.drawy(), tile.block().size);
tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth());
}
}
};
@@ -304,7 +309,7 @@ public class TurretBullets extends BulletList implements ContentList{
}
};
arc = new BulletType(0.001f, 30){
arc = new BulletType(0.001f, 26){
{
lifetime = 1;
despawneffect = Fx.none;

View File

@@ -98,7 +98,7 @@ public class Control extends Module{
"color-1", Color.rgba8888(playerColors[11]),
"color-2", Color.rgba8888(playerColors[13]),
"color-3", Color.rgba8888(playerColors[9]),
"name", "player",
"name", "",
"lastBuild", 0
);
@@ -382,6 +382,10 @@ public class Control extends Module{
}
}
if(Inputs.keyTap("screenshot")){
renderer.takeMapScreenshot();
}
}else{
if(!state.isPaused()){
Timers.update();

View File

@@ -1,6 +1,5 @@
package io.anuke.mindustry.core;
import io.anuke.mindustry.ai.WaveSpawner;
import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.EventType.StateChangeEvent;
import io.anuke.mindustry.game.GameMode;
@@ -12,14 +11,21 @@ import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.waveTeam;
public class GameState{
/**Current wave number, can be anything in non-wave modes.*/
public int wave = 1;
/**Wave countdown in ticks.*/
public float wavetime;
/**Whether the game is in game over state.*/
public boolean gameOver = false;
/**The current game mode.*/
public GameMode mode = GameMode.waves;
/**The current difficulty for wave modes.*/
public Difficulty difficulty = Difficulty.normal;
public WaveSpawner spawner = new WaveSpawner();
/**Team data. Gets reset every new game.*/
public Teams teams = new Teams();
/**Number of enemies in the game; only used clientside in servers.*/
public int enemies;
/**Current game state.*/
private State state = State.menu;
public int enemies(){

View File

@@ -93,7 +93,7 @@ public class Logic extends Module{
}
public void runWave(){
state.spawner.spawnEnemies();
world.spawner.spawnEnemies();
state.wave++;
state.wavetime = wavespace * state.difficulty.timeScaling;

View File

@@ -15,6 +15,7 @@ import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.entities.traits.TypeTrait;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.gen.RemoteReadClient;
import io.anuke.mindustry.net.Net;
@@ -95,6 +96,7 @@ public class NetClient extends Module{
ConnectPacket c = new ConnectPacket();
c.name = player.name;
c.mobile = mobile;
c.versionType = Version.type;
c.color = Color.rgba8888(player.color);
c.usid = getUsid(packet.addressTCP);
c.uuid = Platform.instance.getUUID();

View File

@@ -16,6 +16,7 @@ import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Call;
@@ -24,6 +25,7 @@ import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Administration.PlayerInfo;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
@@ -76,6 +78,9 @@ public class NetServer extends Module{
private DataOutputStream dataStream = new DataOutputStream(syncStream);
public NetServer(){
Events.on(WorldLoadEvent.class, event -> {
connections.clear();
});
Net.handleServer(Connect.class, (id, connect) -> {
if(admins.isIPBanned(connect.addressTCP)){
@@ -120,7 +125,7 @@ public class NetServer extends Module{
return;
}
if(packet.version == -1 && Version.build != -1 && !admins.allowsCustomClients()){
if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals("official")) && Version.build != -1 && !admins.allowsCustomClients())){
kick(id, KickReason.customClient);
return;
}

View File

@@ -10,7 +10,6 @@ import io.anuke.ucore.core.Timers;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.scene.ui.Dialog;
import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.util.Log;
import java.util.Random;
@@ -29,7 +28,6 @@ public abstract class Platform {
if(!mobile) return; //this is mobile only, desktop doesn't need dialogs
field.tapped(() -> {
Log.info("yappd");
Dialog dialog = new Dialog("", "dialog");
dialog.setFillParent(true);
dialog.content().top();

View File

@@ -1,9 +1,16 @@
package io.anuke.mindustry.core;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.PixmapIO;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.BufferUtils;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
@@ -32,6 +39,7 @@ import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.graphics.Surface;
import io.anuke.ucore.modules.RendererModule;
import io.anuke.ucore.scene.utils.Cursors;
import io.anuke.ucore.util.Bundles;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Pooling;
import io.anuke.ucore.util.Translator;
@@ -353,4 +361,44 @@ public class Renderer extends RendererModule{
targetscale = Mathf.clamp(targetscale, Math.round(s * 2), Math.round(s * 5));
}
public void takeMapScreenshot(){
float vpW = Core.camera.viewportWidth, vpH = Core.camera.viewportHeight;
int w = world.width()*tilesize, h = world.height()*tilesize;
int pw = pixelSurface.width(), ph = pixelSurface.height();
showFog = false;
disableUI = true;
pixelSurface.setSize(w, h, true);
Graphics.getEffectSurface().setSize(w, h, true);
Core.camera.viewportWidth = w;
Core.camera.viewportHeight = h;
Core.camera.position.x = w/2f;
Core.camera.position.y = h/2f;
draw();
showFog = true;
disableUI = false;
Core.camera.viewportWidth = vpW;
Core.camera.viewportHeight = vpH;
pixelSurface.getBuffer().begin();
byte[] lines = ScreenUtils.getFrameBufferPixels(0, 0, w, h, true);
for(int i = 0; i < lines.length; i+= 4){
lines[i + 3] = (byte)255;
}
pixelSurface.getBuffer().end();
Pixmap fullPixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
BufferUtils.copy(lines, 0, fullPixmap.getPixels(), lines.length);
FileHandle file = screenshotDirectory.child("screenshot-" + TimeUtils.millis() + ".png");
PixmapIO.writePNG(file, fullPixmap);
fullPixmap.dispose();
pixelSurface.setSize(pw, ph, false);
Graphics.getEffectSurface().setSize(pw, ph, false);
ui.showInfoFade(Bundles.format("text.screenshot", file.toString()));
}
}

View File

@@ -123,6 +123,8 @@ public class UI extends SceneModule{
@Override
public void update(){
if(disableUI) return;
if(Graphics.drawing()) Graphics.end();
act();

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.ai.BlockIndexer;
import io.anuke.mindustry.ai.Pathfinder;
import io.anuke.mindustry.ai.WaveSpawner;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.EventType.TileChangeEvent;
@@ -30,6 +31,7 @@ public class World extends Module{
public final WorldGenerator generator = new WorldGenerator();
public final BlockIndexer indexer = new BlockIndexer();
public final Pathfinder pathfinder = new Pathfinder();
public final WaveSpawner spawner = new WaveSpawner();
private Map currentMap;
private Sector currentSector;

View File

@@ -17,6 +17,8 @@ import static io.anuke.mindustry.Vars.ui;
public enum EditorTool{
pick{
public void touched(MapEditor editor, int x, int y){
if(!Structs.inBounds(x, y, editor.getMap().width(), editor.getMap().height())) return;
byte bf = editor.getMap().read(x, y, DataPosition.floor);
byte bw = editor.getMap().read(x, y, DataPosition.wall);
byte link = editor.getMap().read(x, y, DataPosition.link);

View File

@@ -175,7 +175,6 @@ public class MapView extends Element implements GestureListener{
public void clearStack(){
stack.clear();
//TODO clear und obuffer
}
public OperationStack getStack(){
@@ -292,7 +291,6 @@ public class MapView extends Element implements GestureListener{
}
}
//todo is it really math.max?
float scaling = zoom * Math.min(width, height) / editor.getMap().width();
Draw.color(Palette.accent);

View File

@@ -19,10 +19,7 @@ import io.anuke.mindustry.graphics.Trail;
import io.anuke.mindustry.io.TypeIO;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Mech;
import io.anuke.mindustry.type.Weapon;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
@@ -192,6 +189,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
this.mining = tile;
}
@Override
public boolean canMine(Item item){
return item.hardness <= mech.drillPower;
}
@Override
public float getArmor(){
return mech.armor + mech.getExtraArmor(this);

View File

@@ -209,7 +209,7 @@ public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncT
if(tile == null) return false;
tile = tile.target();
if(tile.entity != null && tile.entity.collide(this) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
if(tile.getTeam() != team){
tile.entity.collision(this);
}

View File

@@ -55,6 +55,10 @@ public abstract class BulletType extends Content implements BaseBulletType<Bulle
despawneffect = BulletFx.hitBulletSmall;
}
public boolean collides(Bullet bullet, Tile tile){
return true;
}
public void hitTile(Bullet b, Tile tile){
hit(b);
}

View File

@@ -58,6 +58,9 @@ public interface BuilderTrait extends Entity{
/**Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all.*/
float getBuildPower(Tile tile);
/**Returns whether or not this builder can mine a specific item type.*/
boolean canMine(Item item);
/**Whether this type of builder can begin creating new blocks.*/
default boolean canCreateBlocks(){
return true;
@@ -236,7 +239,8 @@ public interface BuilderTrait extends Entity{
Tile tile = getMineTile();
TileEntity core = unit.getClosestCore();
if(core == null || tile.block() != Blocks.air || unit.distanceTo(tile.worldx(), tile.worldy()) > mineDistance || tile.floor().drops == null || !unit.inventory.canAcceptItem(tile.floor().drops.item)){
if(core == null || tile.block() != Blocks.air || unit.distanceTo(tile.worldx(), tile.worldy()) > mineDistance
|| tile.floor().drops == null || !unit.inventory.canAcceptItem(tile.floor().drops.item) || !canMine(tile.floor().drops.item)){
setMineTile(null);
}else{
Item item = tile.floor().drops.item;

View File

@@ -1,19 +0,0 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.ucore.entities.trait.HealthTrait;
//TODO implement
public interface RepairTrait extends TeamTrait{
HealthTrait getRepairing();
void setRepairing(HealthTrait trait);
default void drawRepair(){
if(getRepairing() == null) return;
}
default void updateRepair(){
if(getRepairing() == null) return;
}
}

View File

@@ -19,7 +19,6 @@ import io.anuke.ucore.util.Bundles;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Strings;
//TODO merge unit type with mech
public class UnitType extends UnlockableContent{
protected final Supplier<? extends BaseUnit> constructor;

View File

@@ -1,14 +1,11 @@
package io.anuke.mindustry.entities.units.types;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.FlyingUnit;
import io.anuke.mindustry.entities.units.UnitCommand;
@@ -16,7 +13,6 @@ import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.ItemType;
@@ -24,13 +20,11 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Shapes;
import io.anuke.ucore.util.*;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Structs;
import java.io.DataInput;
import java.io.DataOutput;
@@ -117,12 +111,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
if(target.distanceTo(Drone.this) > type.range){
circle(type.range*0.9f);
}else{
TileEntity entity = (TileEntity) target;
entity.healBy(type.healSpeed * entity.tile.block().health / 100f * Timers.delta());
if(timer.get(timerRepairEffect, 30)){
Effects.effect(BlockFx.healBlockFull, Palette.heal, entity.x, entity.y, entity.tile.block().size);
}
getWeapon().update(Drone.this, target.getX(), target.getY());
}
}
},
@@ -279,6 +268,11 @@ public class Drone extends FlyingUnit implements BuilderTrait{
//no
}
@Override
public boolean canMine(Item item){
return type.toMine.contains(item);
}
@Override
public float getBuildPower(Tile tile){
return type.buildPower;
@@ -312,16 +306,6 @@ public class Drone extends FlyingUnit implements BuilderTrait{
target = null;
}
if(Net.client() && state.is(repair) && target instanceof TileEntity && target.distanceTo(this) < type.range){
TileEntity entity = (TileEntity) target;
entity.health += type.healSpeed * Timers.delta();
entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health);
if(timer.get(timerRepairEffect, 30)){
Effects.effect(BlockFx.healBlockFull, Palette.heal, entity.x, entity.y, entity.tile.block().size);
}
}
updateBuilding(this);
}
@@ -349,20 +333,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
@Override
public void drawOver(){
trail.draw(Palette.lightTrail, 3f * Mathf.clamp(velocity.len(), 0, 1f) / 1f);
TargetTrait entity = target;
if(entity instanceof TileEntity && state.is(repair) && target.distanceTo(this) < type.range){
float len = 5f;
Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f));
Shapes.laser("beam", "beam-end",
x + Angles.trnsx(rotation, len),
y + Angles.trnsy(rotation, len),
entity.getX(), entity.getY());
Draw.color();
}
trail.draw(Palette.lightTrail, 3f);
drawBuilding(this);
}

View File

@@ -11,10 +11,10 @@ import java.io.IOException;
public class Version{
/**Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used.*/
public static String type;
/**Number specifying the major version, e.g. '4.0'*/
public static String number;
/**Build modifier, e.g. 'alpha' or 'release'*/
public static String modifier;
/**Number specifying the major version, e.g. '4'*/
public static int number;
/**Build number, e.g. '43'. set to '-1' for custom builds.*/
public static int build = 0;
@@ -26,7 +26,7 @@ public class Version{
PropertiesUtils.load(map, file.reader());
type = map.get("type");
number = map.get("number");
number = Integer.parseInt(map.get("number"));
modifier = map.get("modifier");
build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
}catch(IOException e){

View File

@@ -23,7 +23,7 @@ import static io.anuke.ucore.core.Core.camera;
public class BlockRenderer{
private final static int initialRequests = 32 * 32;
private final static int expandr = 4;
private final static int expandr = 6;
public final FloorRenderer floor = new FloorRenderer();

View File

@@ -157,17 +157,14 @@ public class Shaders{
@Override
public void apply(){
// shader.setUniformf("u_progress", progress);
shader.setUniformf("u_color", color);
shader.setUniformf("u_uv", region.getU(), region.getV());
shader.setUniformf("u_uv2", region.getU2(), region.getV2());
//shader.setUniformf("u_time", Timers.time());
shader.setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight());
}
}
public static class Shield extends Shader{
//public Color color = new Color();
public Shield(){
super("shield", "default");
@@ -175,17 +172,13 @@ public class Shaders{
@Override
public void apply(){
float scaling = Core.cameraScale / 4f / Core.camera.zoom;
shader.setUniformf("u_dp", Unit.dp.scl(1f));
//shader.setUniformf("u_color", color);
shader.setUniformf("u_time", Timers.time() / Unit.dp.scl(1f));
shader.setUniformf("u_scaling", scaling);
shader.setUniformf("u_offset",
Core.camera.position.x - Core.camera.viewportWidth / 2 * Core.camera.zoom,
Core.camera.position.y - Core.camera.viewportHeight / 2 * Core.camera.zoom);
shader.setUniformf("u_texsize", Gdx.graphics.getWidth() / Core.cameraScale * Core.camera.zoom,
Gdx.graphics.getHeight() / Core.cameraScale * Core.camera.zoom);
shader.setUniformf("u_texsize", Core.camera.viewportWidth * Core.camera.zoom,
Core.camera.viewportHeight * Core.camera.zoom);
}
}
@@ -200,8 +193,8 @@ public class Shaders{
shader.setUniformf("camerapos",
Core.camera.position.x - Core.camera.viewportWidth / 2 * Core.camera.zoom,
Core.camera.position.y - Core.camera.viewportHeight / 2 * Core.camera.zoom);
shader.setUniformf("screensize", Gdx.graphics.getWidth() / Core.cameraScale * Core.camera.zoom,
Gdx.graphics.getHeight() / Core.cameraScale * Core.camera.zoom);
shader.setUniformf("screensize", Core.camera.viewportWidth* Core.camera.zoom,
Core.camera.viewportHeight * Core.camera.zoom);
shader.setUniformf("time", Timers.time());
}
}

View File

@@ -32,6 +32,7 @@ public class DefaultKeybinds{
"menu", Gdx.app.getType() == ApplicationType.Android ? Input.BACK : Input.ESCAPE,
"pause", Input.SPACE,
"toggle_menus", Input.C,
"screenshot", Input.P,
new Category("multiplayer"),
"player_list", Input.TAB,
"chat", Input.ENTER,

View File

@@ -193,7 +193,7 @@ public abstract class InputHandler extends InputAdapter{
}
//call tapped event
if(tile.getTeam() == player.getTeam()){
if(!consumed && tile.getTeam() == player.getTeam()){
Call.onTileTapped(player, tile);
}

View File

@@ -230,7 +230,7 @@ public class MobileInput extends InputHandler implements GestureListener{
player.clearBuilding();
mode = none;
recipe = null;
}).visible(() -> player.isBuilding() || recipe != null);
}).visible(() -> player.isBuilding() || recipe != null || mode == breaking);
//confirm button
table.addImageButton("icon-check", "clear-partial", 16 * 2f, () -> {
@@ -528,7 +528,7 @@ public class MobileInput extends InputHandler implements GestureListener{
//ignore off-screen taps
if(cursor == null || ui.hasMouse(x, y)) return false;
threads.run(() -> checkTargets(worldx, worldy));
checkTargets(worldx, worldy);
//remove if request present
if(hasRequest(cursor)){
@@ -548,14 +548,13 @@ public class MobileInput extends InputHandler implements GestureListener{
consumed = true;
player.dropCarry(); //drop off unit
}else{
threads.run(() -> {
Unit unit = Units.getClosest(player.getTeam(), Graphics.world(x, y).x, Graphics.world(x, y).y, 4f, u -> !u.isFlying() && u.getMass() <= player.mech.carryWeight);
Unit unit = Units.getClosest(player.getTeam(), Graphics.world(x, y).x, Graphics.world(x, y).y, 4f, u -> !u.isFlying() && u.getMass() <= player.mech.carryWeight);
if(unit != null){
player.moveTarget = unit;
Effects.effect(Fx.select, unit.getX(), unit.getY());
}
});
if(unit != null){
consumed = true;
player.moveTarget = unit;
Effects.effect(Fx.select, unit.getX(), unit.getY());
}
}
}

View File

@@ -0,0 +1,43 @@
package io.anuke.mindustry.io;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.function.Consumer;
import static io.anuke.mindustry.Vars.contributorsURL;
public class Contributors{
public static void getContributors(Consumer<Array<Contributor>> success, Consumer<Throwable> fail){
Net.http(contributorsURL, "GET", result -> {
JsonReader reader = new JsonReader();
JsonValue value = reader.parse(result).child;
Array<Contributor> out = new Array<>();
while(value != null){
String login = value.getString("login");
out.add(new Contributor(login));
value = value.next;
}
success.accept(out);
}, fail);
}
public static class Contributor{
public final String login;
public Contributor(String login){
this.login = login;
}
@Override
public String toString(){
return "Contributor{" +
"login='" + login + '\'' +
'}';
}
}
}

View File

@@ -27,7 +27,6 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static io.anuke.mindustry.Vars.*;
@@ -332,31 +331,21 @@ public class TypeIO{
@WriteClass(String.class)
public static void writeString(ByteBuffer buffer, String string){
if(string != null){
Charset charset = Charset.defaultCharset();
byte[] nameBytes = charset.name().getBytes(StandardCharsets.UTF_8);
buffer.put((byte)nameBytes.length);
buffer.put(nameBytes);
byte[] bytes = string.getBytes(charset);
byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
buffer.putShort((short) bytes.length);
buffer.put(bytes);
}else{
buffer.put((byte) -1);
buffer.putShort((short) -1);
}
}
@ReadClass(String.class)
public static String readString(ByteBuffer buffer){
byte length = buffer.get();
if(length != -1){
byte[] cbytes = new byte[length];
buffer.get(cbytes);
Charset charset = Charset.forName(new String(cbytes, StandardCharsets.UTF_8));
short slength = buffer.getShort();
short slength = buffer.getShort();
if(slength != -1){
byte[] bytes = new byte[slength];
buffer.get(bytes);
return new String(bytes, charset);
return new String(bytes, StandardCharsets.UTF_8);
}else{
return null;
}
@@ -378,30 +367,20 @@ public class TypeIO{
public static void writeStringData(DataOutput buffer, String string) throws IOException{
if(string != null){
Charset charset = Charset.defaultCharset();
byte[] nameBytes = charset.name().getBytes(StandardCharsets.UTF_8);
buffer.writeByte((byte)nameBytes.length);
buffer.write(nameBytes);
byte[] bytes = string.getBytes(charset);
byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
buffer.writeShort((short) bytes.length);
buffer.write(bytes);
}else{
buffer.writeByte((byte) -1);
buffer.writeShort((short) -1);
}
}
public static String readStringData(DataInput buffer) throws IOException{
byte length = buffer.readByte();
if(length != -1){
byte[] cbytes = new byte[length];
buffer.readFully(cbytes);
Charset charset = Charset.forName(new String(cbytes, StandardCharsets.UTF_8));
short slength = buffer.readShort();
short slength = buffer.readShort();
if(slength != -1){
byte[] bytes = new byte[slength];
buffer.readFully(bytes);
return new String(bytes, charset);
return new String(bytes, StandardCharsets.UTF_8);
}else{
return null;
}

View File

@@ -45,7 +45,7 @@ public class Save16 extends SaveFileVersion{
content.setTemporaryMapper(readContentHeader(stream));
state.spawner.read(stream);
world.spawner.read(stream);
readEntities(stream);
@@ -71,7 +71,7 @@ public class Save16 extends SaveFileVersion{
writeContentHeader(stream);
state.spawner.write(stream); //spawnes
world.spawner.write(stream); //spawnes
//--ENTITIES--

View File

@@ -32,4 +32,13 @@ public class Map{
public String getDisplayName(){
return meta.tags.get("name", name);
}
@Override
public String toString(){
return "Map{" +
"name='" + name + '\'' +
", custom=" + custom +
", meta=" + meta +
'}';
}
}

View File

@@ -37,4 +37,13 @@ public class MapMeta{
public boolean hasOreGen(){
return !tags.get("oregen", "0").equals("0");
}
@Override
public String toString(){
return "MapMeta{" +
"tags=" + tags +
", width=" + width +
", height=" + height +
'}';
}
}

View File

@@ -30,7 +30,7 @@ public class TutorialSector{
new ItemMission(Items.copper, 100).setMessage("$tutorial.morecopper"),
new BlockMission(TurretBlocks.duo).setMessage("$tutorial.turret"),
//TODO fill turret with items mission
/
//new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.drillturret"),
// Create a wave mission which spawns the core at 60, 60 rather than in the center of the map

View File

@@ -30,7 +30,6 @@ public class Generation{
return tiles[x][y];
}
//TODO implement
Item drillItem(int x, int y, Drill block){
if(block.isMultiblock()){
Item result = null;

View File

@@ -172,6 +172,25 @@ public class WorldGenerator{
prepareTiles(tiles);
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Tile tile = tiles[x][y];
byte elevation = tile.getElevation();
for(GridPoint2 point : Geometry.d4){
if(!Structs.inBounds(x + point.x, y + point.y, width, height)) continue;
if(tiles[x + point.x][y + point.y].getElevation() < elevation){
if(sim2.octaveNoise2D(1, 1, 1.0 / 8, x, y) > 0.8){
tile.setElevation(-1);
}
break;
}
}
}
}
world.setBlock(tiles[spawns.get(0).x][spawns.get(0).y], StorageBlocks.core, Team.blue);
if(state.mode.isPvp){

View File

@@ -356,12 +356,13 @@ public class Net{
Gdx.net.sendHttpRequest(req, new HttpResponseListener(){
@Override
public void handleHttpResponse(HttpResponse httpResponse){
listener.accept(httpResponse.getResultAsString());
String result = httpResponse.getResultAsString();
Gdx.app.postRunnable(() -> listener.accept(result));
}
@Override
public void failed(Throwable t){
failure.accept(t);
Gdx.app.postRunnable(() -> failure.accept(t));
}
@Override

View File

@@ -2,7 +2,7 @@ package io.anuke.mindustry.net;
import com.badlogic.gdx.utils.Base64Coder;
import io.anuke.mindustry.game.Version;
import io.anuke.ucore.io.IOUtils;
import io.anuke.mindustry.io.TypeIO;
import io.anuke.ucore.util.Bundles;
import java.nio.ByteBuffer;
@@ -65,6 +65,7 @@ public class Packets{
public static class ConnectPacket implements Packet{
public int version;
public String versionType;
public String name, uuid, usid;
public boolean mobile;
public int color;
@@ -72,8 +73,9 @@ public class Packets{
@Override
public void write(ByteBuffer buffer){
buffer.putInt(Version.build);
IOUtils.writeString(buffer, name);
IOUtils.writeString(buffer, usid);
TypeIO.writeString(buffer, versionType);
TypeIO.writeString(buffer, name);
TypeIO.writeString(buffer, usid);
buffer.put(mobile ? (byte) 1 : 0);
buffer.putInt(color);
buffer.put(Base64Coder.decode(uuid));
@@ -82,8 +84,9 @@ public class Packets{
@Override
public void read(ByteBuffer buffer){
version = buffer.getInt();
name = IOUtils.readString(buffer);
usid = IOUtils.readString(buffer);
versionType = TypeIO.readString(buffer);
name = TypeIO.readString(buffer);
usid = TypeIO.readString(buffer);
mobile = buffer.get() == 1;
color = buffer.getInt();
byte[] idbytes = new byte[8];

View File

@@ -1,8 +1,6 @@
package io.anuke.mindustry.type;
/**
* Used to store ammo amounts in units and turrets.
*/
/**Used to store ammo amounts in turrets.*/
public class AmmoEntry{
public AmmoType type;
public int amount;

View File

@@ -11,7 +11,6 @@ import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Bundles;
//TODO merge unit type with mech
public class Mech extends UnlockableContent{
public final String name;
public final String description;

View File

@@ -2,7 +2,11 @@ package io.anuke.mindustry.ui.dialogs;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectSet;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.io.Contributors;
import io.anuke.mindustry.io.Contributors.Contributor;
import io.anuke.mindustry.ui.Links;
import io.anuke.mindustry.ui.Links.LinkEntry;
import io.anuke.ucore.core.Core;
@@ -18,11 +22,14 @@ import static io.anuke.mindustry.Vars.ios;
import static io.anuke.mindustry.Vars.ui;
public class AboutDialog extends FloatingDialog{
private Array<Contributor> contributors = new Array<>();
private static ObjectSet<String> bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "trello");
public AboutDialog(){
super("$text.about.button");
Contributors.getContributors(out -> contributors = out, Throwable::printStackTrace);
shown(this::setup);
onResize(this::setup);
}
@@ -94,7 +101,24 @@ public class AboutDialog extends FloatingDialog{
public void showCredits(){
FloatingDialog dialog = new FloatingDialog("$text.credits");
dialog.addCloseButton();
dialog.content().labelWrap("$text.credits.text").width(400f);
dialog.content().add("$text.credits.text");
dialog.content().row();
if(!contributors.isEmpty()){
dialog.content().addImage("blank").color(Palette.accent).fillX().height(3f).pad(3f);
dialog.content().row();
dialog.content().add("$text.contributors");
dialog.content().row();
dialog.content().pane("clear", new Table(){{
int i = 0;
left();
for(Contributor c : contributors){
add("[lightgray]" + c.login).left().pad(3).padLeft(6).padRight(6);
if(++i % 3 == 0){
row();
}
}
}});
}
dialog.show();
}
}

View File

@@ -28,7 +28,6 @@ public class HostDialog extends FloatingDialog{
content().table(t -> {
t.add("$text.name").padRight(10);
t.addField(Settings.getString("name"), text -> {
if(text.isEmpty()) return;
player.name = text;
Settings.put("name", text);
Settings.save();
@@ -50,6 +49,11 @@ public class HostDialog extends FloatingDialog{
content().add().width(65f);
content().addButton("$text.host", () -> {
if(Settings.getString("name").trim().isEmpty()){
ui.showInfo("$text.noname");
return;
}
ui.loadfrag.show("$text.hosting");
Timers.runTask(5f, () -> {
try{

View File

@@ -205,7 +205,6 @@ public class JoinDialog extends FloatingDialog{
content().table(t -> {
t.add("$text.name").padRight(10);
t.addField(Settings.getString("name"), text -> {
if(text.isEmpty()) return;
player.name = text;
Settings.put("name", text);
Settings.save();
@@ -285,6 +284,11 @@ public class JoinDialog extends FloatingDialog{
}
void connect(String ip, int port){
if(Settings.getString("name").trim().isEmpty()){
ui.showInfo("$text.noname");
return;
}
ui.loadfrag.show("$text.connecting");
ui.loadfrag.setButton(() -> {

View File

@@ -1,5 +1,7 @@
package io.anuke.mindustry.ui.fragments;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
@@ -8,13 +10,13 @@ import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.Group;
import io.anuke.ucore.scene.ui.Dialog;
import io.anuke.ucore.scene.ui.Label;
import io.anuke.ucore.scene.ui.Label.LabelStyle;
import io.anuke.ucore.scene.ui.TextField;
@@ -22,8 +24,7 @@ import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.players;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.ucore.core.Core.scene;
import static io.anuke.ucore.core.Core.skin;
@@ -113,9 +114,35 @@ public class ChatFragment extends Table{
chatfield.getStyle().font = skin.getFont("default-font-chat");
chatfield.getStyle().fontColor = Color.WHITE;
chatfield.setStyle(chatfield.getStyle());
Platform.instance.addDialog(chatfield, Vars.maxTextLength);
bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(4f);
if(mobile){
chatfield.tapped(() -> {
Dialog dialog = new Dialog("", "dialog");
dialog.setFillParent(true);
dialog.content().top();
dialog.content().defaults().height(65f);
TextField to = dialog.content().addField("", t-> {}).pad(15).width(250f).get();
to.setMaxLength(maxTextLength);
to.keyDown(Keys.ENTER, () -> dialog.content().find("okb").fireClick());
dialog.content().addButton("$text.ok", () -> {
chatfield.clearText();
chatfield.appendText(to.getText());
chatfield.change();
dialog.hide();
Gdx.input.setOnscreenKeyboardVisible(false);
toggle();
}).width(90f).name("okb");
dialog.show();
Timers.runTask(1f, () -> {
to.setCursorPosition(to.getText().length());
Core.scene.setKeyboardFocus(to);
Gdx.input.setOnscreenKeyboardVisible(true);
});
});
}
bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(6f);
add(chatfield).padBottom(offsety).padLeft(offsetx).growX().padRight(offsetx).height(28);
@@ -123,10 +150,6 @@ public class ChatFragment extends Table{
marginBottom(105f);
marginRight(240f);
}
if(Vars.mobile){
addImageButton("icon-arrow-right", 14 * 2, this::toggle).size(46f, 51f).visible(() -> chatOpen).pad(2f);
}
}
@Override

View File

@@ -11,6 +11,7 @@ import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.scene.Group;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Strings;
import static io.anuke.mindustry.Vars.*;
@@ -42,7 +43,7 @@ public class MenuFragment extends Fragment{
}
//version info
parent.fill(c -> c.bottom().left().add("Mindustry " + Version.number + "-" + Version.modifier + " " + Version.type + " / " + (Version.build == -1 ? "custom build" : "build " + Version.build))
parent.fill(c -> c.bottom().left().add(Strings.formatArgs("Mindustry v{0} {1}-{2} {3}", Version.number, Version.modifier, Version.type, (Version.build == -1 ? "custom build" : "build " + Version.build)))
.visible(() -> state.is(State.menu)));
}
@@ -55,14 +56,14 @@ public class MenuFragment extends Fragment{
container.defaults().size(size).pad(5).padTop(4f);
MobileButton
play = new MobileButton("icon-play-2", isize, "$text.play", this::showPlaySelect),
maps = new MobileButton("icon-map", isize, "$text.maps", ui.maps::show),
load = new MobileButton("icon-load", isize, "$text.load", ui.load::show),
join = new MobileButton("icon-add", isize, "$text.joingame", ui.join::show),
editor = new MobileButton("icon-editor", isize, "$text.editor", () -> ui.loadGraphics(ui.editor::show)),
tools = new MobileButton("icon-tools", isize, "$text.settings", ui.settings::show),
unlocks = new MobileButton("icon-unlocks", isize, "$text.unlocks", ui.unlocks::show),
donate = new MobileButton("icon-donate", isize, "$text.donate", Platform.instance::openDonations);
play = new MobileButton("icon-play-2", isize, "$text.play", this::showPlaySelect),
maps = new MobileButton("icon-map", isize, "$text.maps", ui.maps::show),
load = new MobileButton("icon-load", isize, "$text.load", ui.load::show),
join = new MobileButton("icon-add", isize, "$text.joingame", ui.join::show),
editor = new MobileButton("icon-editor", isize, "$text.editor", () -> ui.loadGraphics(ui.editor::show)),
tools = new MobileButton("icon-tools", isize, "$text.settings", ui.settings::show),
unlocks = new MobileButton("icon-unlocks", isize, "$text.unlocks", ui.unlocks::show),
donate = new MobileButton("icon-donate", isize, "$text.donate", Platform.instance::openDonations);
if(Gdx.graphics.getWidth() > Gdx.graphics.getHeight()){
container.add(play);

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.ui.fragments;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.EventType.WorldLoadGraphicsEvent;
@@ -33,7 +34,7 @@ public class PlacementFragment extends Fragment{
Category currentCategory = Category.turret;
Block hovered, lastDisplay;
Tile hoverTile;
Table blockTable, toggler;
Table blockTable, toggler, topTable;
boolean shown = true;
public PlacementFragment(){
@@ -106,6 +107,7 @@ public class PlacementFragment extends Fragment{
//top table with hover info
frame.table("clear", top -> {
topTable = top;
top.add(new Table()).growX().update(topTable -> {
if((tileDisplayBlock() == null && lastDisplay == getSelected()) ||
(tileDisplayBlock() != null && lastDisplay == tileDisplayBlock())) return;
@@ -194,8 +196,10 @@ public class PlacementFragment extends Fragment{
Block getSelected(){
Block toDisplay = null;
Vector2 v = topTable.stageToLocalCoordinates(Graphics.mouse());
//setup hovering tile
if(!ui.hasMouse()){
if(!ui.hasMouse() && topTable.hit(v.x, v.y, false) == null){
Tile tile = world.tileWorld(Graphics.mouseWorld().x, Graphics.mouseWorld().y);
if(tile != null){
hoverTile = tile.target();

View File

@@ -43,7 +43,7 @@ public abstract class BaseBlock extends MappableContent{
/**Returns the amount of items this block can accept.*/
public int acceptStack(Item item, int amount, Tile tile, Unit source){
if(acceptItem(item, tile, tile) && hasItems && (source == null || source.getTeam() == tile.getTeam())){
return Math.min(getMaximumAccepted(tile, item), amount);
return Math.min(getMaximumAccepted(tile, item) - tile.entity.items.get(item), amount);
}else{
return 0;
}

View File

@@ -150,7 +150,7 @@ public class Block extends BaseBlock {
TileEntity entity = tile.entity();
for(Tile other : getPowerConnections(tile, tempTiles)){
if(other.entity.power != null){
if(other.entity.power != null && other.entity.power.graph != null){
other.entity.power.graph.add(entity.power.graph);
}
}
@@ -331,7 +331,6 @@ public class Block extends BaseBlock {
if(hasItems) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items);
}
//TODO make this easier to config.
public void setBars(){
if(hasPower) bars.add(new BlockBar(BarType.power, true, tile -> tile.entity.power.amount / powerCapacity));
if(hasLiquids)

View File

@@ -241,7 +241,7 @@ public class Tile implements PosTrait, TargetTrait{
if(link == 0){
return (block.destructible || block.breakable || block.update);
}else{
return getLinked() != this && getLinked().breakable();
return getLinked() != this && getLinked().getLinked() == null && getLinked().breakable();
}
}

View File

@@ -191,7 +191,7 @@ public class Floor extends Block{
if(floor instanceof OreBlock) floor = ((OreBlock) floor).base;
if(cur instanceof OreBlock) cur = ((OreBlock) cur).base;
if((floor.id <= cur.id && !(tile.getElevation() != -1 && other.getElevation() > tile.getElevation())) || (!cur.blends.test(floor) && !cur.tileBlends.test(tile, other)) || (floor.cacheLayer.ordinal() > cur.cacheLayer.ordinal() && !sameLayer) ||
if(floor.edgeRegions == null || (floor.id <= cur.id && !(tile.getElevation() != -1 && other.getElevation() > tile.getElevation())) || (!cur.blends.test(floor) && !cur.tileBlends.test(tile, other)) || (floor.cacheLayer.ordinal() > cur.cacheLayer.ordinal() && !sameLayer) ||
(sameLayer && floor.cacheLayer == cur.cacheLayer)) continue;
TextureRegion region = floor.edgeRegions[i];

View File

@@ -95,8 +95,11 @@ public class MendProjector extends Block{
@Override
public void drawSelect(Tile tile){
MendEntity entity = tile.entity();
float realRange = range + entity.phaseHeat * phaseRangeBoost;
Draw.color(color);
Lines.dashCircle(tile.drawx(), tile.drawy() - 1f, range);
Lines.dashCircle(tile.drawx(), tile.drawy(), realRange);
Draw.color();
}

View File

@@ -1,58 +0,0 @@
package io.anuke.mindustry.world.blocks.defense;
import com.badlogic.gdx.graphics.Color;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.defense.DeflectorWall.DeflectorEntity;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.tilesize;
public class MendingWall extends Wall{
protected float regenSpeed = 0.25f;
public MendingWall(String name){
super(name);
update = true;
}
@Override
public void handleBulletHit(TileEntity entity, Bullet bullet){
super.handleBulletHit(entity, bullet);
((DeflectorEntity) entity).hit = 1f;
}
@Override
public void draw(Tile tile){
super.draw(tile);
DeflectorEntity entity = tile.entity();
if(entity.hit < 0.0001f) return;
Graphics.setAdditiveBlending();
Draw.color(Color.WHITE);
Draw.alpha(entity.hit * 0.5f);
Draw.rect("blank", tile.drawx(), tile.drawy(), tilesize * size, tilesize * size);
Draw.reset();
entity.hit = Mathf.clamp(entity.hit - Timers.delta() / DeflectorWall.hitTime);
Graphics.setNormalBlending();
}
@Override
public void update(Tile tile){
tile.entity.health = Mathf.clamp(tile.entity.health + regenSpeed * Timers.delta(), 0f, health);
}
@Override
public TileEntity newEntity(){
return new DeflectorEntity();
}
}

View File

@@ -36,6 +36,7 @@ public class OverdriveProjector extends Block{
protected float speedBoost = 1.5f;
protected float speedBoostPhase = 0.75f;
protected float useTime = 400f;
protected float phaseRangeBoost = 20f;
public OverdriveProjector(String name){
super(name);
@@ -66,7 +67,7 @@ public class OverdriveProjector extends Block{
}
if(entity.charge >= reload){
float realRange = range + entity.phaseHeat * 20f;
float realRange = range + entity.phaseHeat * phaseRangeBoost;
float realBoost = speedBoost + entity.phaseHeat*speedBoostPhase;
Effects.effect(BlockFx.overdriveWave, Hue.mix(color, phase, entity.phaseHeat), tile.drawx(), tile.drawy(), realRange);
@@ -97,8 +98,11 @@ public class OverdriveProjector extends Block{
@Override
public void drawSelect(Tile tile){
OverdriveEntity entity = tile.entity();
float realRange = range + entity.phaseHeat * phaseRangeBoost;
Draw.color(color);
Lines.dashCircle(tile.drawx(), tile.drawy() - 1f, range);
Lines.dashCircle(tile.drawx(), tile.drawy(), realRange);
Draw.color();
}

View File

@@ -1,6 +1,5 @@
package io.anuke.mindustry.world.blocks.distribution;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.NumberUtils;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.type.Item;
@@ -8,10 +7,9 @@ import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.util.Bits;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.content;
public class Junction extends Block{
protected float speed = 26; //frames taken to go through this junction
@@ -34,8 +32,8 @@ public class Junction extends Block{
public void update(Tile tile){
JunctionEntity entity = tile.entity();
for(int i = 0; i < 2; i++){
Buffer buffer = (i == 0 ? entity.bx : entity.by);
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;
@@ -44,17 +42,11 @@ public class Junction extends Block{
if(Timers.time() >= time + speed || Timers.time() < time){
int val = Bits.getRightInt(l);
Item item = content.item(Bits.getLeftShort(val));
int direction = Bits.getRightShort(val);
Tile dest = tile.getNearby(direction);
Item item = content.item(Bits.getRightInt(l));
Tile dest = tile.getNearby(i);
//skip blocks that don't want the item, keep waiting until they do
if(dest == null || !dest.block().acceptItem(item, dest, tile)){
if(buffer.index > 1 && Bits.getRightShort(Bits.getRightInt(buffer.items[1])) != direction){
System.arraycopy(buffer.items, 1, buffer.items, 0, buffer.index - 1);
buffer.index--;
}
continue;
}
@@ -69,25 +61,19 @@ public class Junction extends Block{
@Override
public void handleItem(Item item, Tile tile, Tile source){
JunctionEntity entity = tile.entity();
boolean x = tile.x == source.x;
long value = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), Bits.packInt((short) item.id, source.relativeTo(tile.x, tile.y)));
if(x){
entity.bx.add(value);
}else{
entity.by.add(value);
}
long value = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), item.id);
int relative = source.relativeTo(tile.x, tile.y);
entity.buffers[relative].add(value);
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
JunctionEntity entity = tile.entity();
boolean x = tile.x == source.x;
int relative = source.relativeTo(tile.x, tile.y);
if(entity == null || entity.bx == null || entity.by == null || (x && entity.bx.full()) || (!x && entity.by.full()))
if(entity == null || relative == -1 || entity.buffers[relative].full())
return false;
int dir = source.relativeTo(tile.x, tile.y);
if(dir == -1) return false;
Tile to = tile.getNearby(dir);
Tile to = tile.getNearby(relative);
return to != null && to.block().acceptItem(item, to, tile);
}
@@ -96,41 +82,8 @@ public class Junction extends Block{
return new JunctionEntity();
}
@Override
public Array<Object> getDebugInfo(Tile tile){
JunctionEntity entity = tile.entity();
Array<Object> arr = super.getDebugInfo(tile);
for(int i = 0; i < 4; i++){
arr.add("nearby." + i);
arr.add(tile.getNearby(i));
}
Consumer<Buffer> write = b -> {
for(int i = 0; i < b.index; i++){
long l = b.items[i];
float time = NumberUtils.intBitsToFloat(Bits.getLeftInt(l));
int val = Bits.getRightInt(l);
Item item = content.item(Bits.getLeftShort(val));
int direction = Bits.getRightShort(val);
Tile dest = tile.getNearby(direction);
arr.add(" bufferx.item");
arr.add(time + " | " + item.name + " | " + dest.block() + ":" + dest.floor());
}
};
arr.add("buffer.bx");
arr.add(entity.bx.index);
write.accept(entity.bx);
arr.add("buffer.by");
arr.add(entity.bx.index);
write.accept(entity.by);
return arr;
}
class JunctionEntity extends TileEntity{
Buffer bx = new Buffer();
Buffer by = new Buffer();
Buffer[] buffers = {new Buffer(), new Buffer(), new Buffer(), new Buffer()};
}
class Buffer{

View File

@@ -4,7 +4,6 @@ import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.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;
@@ -13,13 +12,17 @@ import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Mathf;
import io.anuke.mindustry.gen.Call;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.content;
import static io.anuke.mindustry.Vars.threads;
public class Sorter extends Block implements SelectionTrait{
private static Item lastItem;
public Sorter(String name){
super(name);
@@ -35,6 +38,13 @@ public class Sorter extends Block implements SelectionTrait{
return true;
}
@Override
public void playerPlaced(Tile tile){
if(lastItem != null){
threads.runDelay(() -> Call.setSorterItem(null, tile, lastItem));
}
}
@Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void setSorterItem(Player player, Tile tile, Item item){
SorterEntity entity = tile.entity();
@@ -45,8 +55,6 @@ public class Sorter extends Block implements SelectionTrait{
public void draw(Tile tile){
super.draw(tile);
//TODO call event for change
SorterEntity entity = tile.entity();
Draw.color(entity.sortItem.color);
@@ -110,7 +118,10 @@ public class Sorter extends Block implements SelectionTrait{
@Override
public void buildTable(Tile tile, Table table){
SorterEntity entity = tile.entity();
buildItemTable(table, () -> entity.sortItem, item -> Call.setSorterItem(null, tile, item));
buildItemTable(table, () -> entity.sortItem, item -> {
lastItem = item;
Call.setSorterItem(null, tile, item);
});
}
@Override

View File

@@ -5,7 +5,6 @@ import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
@@ -30,7 +29,6 @@ public abstract class ItemLiquidGenerator extends ItemGenerator{
@Override
public void init(){
super.init();
stats.remove(BlockStat.liquidFuelUse);
}
@Override

View File

@@ -4,7 +4,6 @@ import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.consumers.ConsumeLiquid;
//TODO
public class TurbineGenerator extends BurnerGenerator{
public TurbineGenerator(String name){

View File

@@ -42,7 +42,7 @@ public class Cultivator extends Drill{
stats.remove(BlockStat.drillTier);
stats.add(BlockStat.drillTier, table -> {
table.addImage("grass1").size(8 * 3).padBottom(3).padTop(3);
// TODO: find out localized name and add tool tip
table.add(Blocks.grass.formalName).padLeft(3);
});
}

View File

@@ -21,6 +21,7 @@ public class LiquidMixer extends LiquidBlock{
hasItems = true;
rotate = false;
solid = true;
singleLiquid = false;
outputsLiquid = true;
}

View File

@@ -152,11 +152,6 @@ public class Smelter extends Block{
Effects.effect(craftEffect, flameColor, tile.drawx(), tile.drawy());
}
@Override
public int getMaximumAccepted(Tile tile, Item item){
return itemCapacity;
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
boolean isInput = false;

View File

@@ -11,8 +11,8 @@ import io.anuke.ucore.scene.ui.layout.Table;
import static io.anuke.mindustry.Vars.mobile;
public abstract class Consume{
private boolean optional;
private boolean update = true;
protected boolean optional;
protected boolean update = true;
public Consume optional(boolean optional){
this.optional = optional;

View File

@@ -53,6 +53,6 @@ public class ConsumeItem extends Consume{
@Override
public void display(BlockStats stats){
stats.add(BlockStat.inputItem, item);
stats.add(optional ? BlockStat.boostItem : BlockStat.inputItem, item);
}
}

View File

@@ -58,6 +58,6 @@ public class ConsumeItemFilter extends Consume{
@Override
public void display(BlockStats stats){
stats.add(BlockStat.inputItems, new ItemFilterValue(filter));
stats.add(optional ? BlockStat.boostItem : BlockStat.inputItem, new ItemFilterValue(filter));
}
}

View File

@@ -44,6 +44,6 @@ public class ConsumeItems extends Consume{
@Override
public void display(BlockStats stats){
stats.add(BlockStat.inputItems, new ItemListValue(items));
stats.add(optional ? BlockStat.boostItem : BlockStat.inputItems, new ItemListValue(items));
}
}

View File

@@ -32,7 +32,7 @@ public class ConsumeLiquid extends Consume{
@Override
public String getIcon(){
return "icon-liquid";
return "icon-liquid-small";
}
@Override
@@ -47,8 +47,12 @@ public class ConsumeLiquid extends Consume{
@Override
public void display(BlockStats stats){
stats.add(BlockStat.liquidUse, use * 60f, StatUnit.liquidSecond);
stats.add(BlockStat.inputLiquid, liquid);
if(!optional){
stats.add(BlockStat.liquidUse, use * 60f, StatUnit.liquidSecond);
stats.add(BlockStat.inputLiquid, liquid);
}else{
stats.add(BlockStat.boostLiquid, liquid);
}
}
float use(Block block, TileEntity entity){

View File

@@ -47,7 +47,7 @@ public class ConsumeLiquidFilter extends Consume{
@Override
public String getIcon(){
return "icon-liquid";
return "icon-liquid-small";
}
@Override
@@ -62,10 +62,12 @@ public class ConsumeLiquidFilter extends Consume{
@Override
public void display(BlockStats stats){
if(isFuel){
if(optional){
stats.add(BlockStat.boostLiquid, new LiquidFilterValue(filter));
}else if(isFuel){
stats.add(BlockStat.inputLiquidFuel, new LiquidFilterValue(filter));
stats.add(BlockStat.liquidFuelUse, 60f * use, StatUnit.liquidSecond);
}else{
}else {
stats.add(BlockStat.inputLiquid, new LiquidFilterValue(filter));
stats.add(BlockStat.liquidUse, 60f * use, StatUnit.liquidSecond);
}

View File

@@ -21,7 +21,7 @@ public class ConsumePower extends Consume{
@Override
public String getIcon(){
return "icon-power";
return "icon-power-small";
}
@Override

View File

@@ -45,8 +45,10 @@ public enum BlockStat{
shots(StatCategory.shooting),
reload(StatCategory.shooting),
powerShot(StatCategory.shooting),
targetsAir(StatCategory.shooting),;
targetsAir(StatCategory.shooting),
boostItem(StatCategory.optional),
boostLiquid(StatCategory.optional),;
public final StatCategory category;

View File

@@ -12,9 +12,7 @@ import io.anuke.ucore.util.Log;
import java.util.Locale;
/**
* Hold and organizes a list of block stats.
*/
/**Hold and organizes a list of block stats.*/
public class BlockStats{
private static final boolean errorWhenMissing = false;
@@ -26,52 +24,37 @@ public class BlockStats{
this.block = block;
}
/**
* Adds a single float value with this stat, formatted to 2 decimal places.
*/
/**Adds a single float value with this stat, formatted to 2 decimal places.*/
public void add(BlockStat stat, float value, StatUnit unit){
add(stat, new NumberValue(value, unit));
}
/**
* Adds a single y/n boolean value.
*/
/**Adds a single y/n boolean value.*/
public void add(BlockStat stat, boolean value){
add(stat, new BooleanValue(value));
}
/**
* Adds an item value.
*/
/**Adds an item value.*/
public void add(BlockStat stat, Item item){
add(stat, new ItemValue(new ItemStack(item, 1)));
}
/**
* Adds a liquid value.
*/
/**Adds a liquid value.*/
public void add(BlockStat stat, Liquid liquid){
add(stat, new LiquidValue(liquid));
}
/**
* Adds an item value.
*/
/**Adds an item value.*/
public void add(BlockStat stat, ItemStack item){
add(stat, new ItemValue(item));
}
/**
* Adds a single string value with this stat.
*/
/**Adds a single string value with this stat.*/
public void add(BlockStat stat, String format, Object... args){
add(stat, new StringValue(format, args));
}
/**
* Adds a stat value.
*/
/**Adds a stat value.*/
public void add(BlockStat stat, StatValue value){
if(!Bundles.has("text.blocks." + stat.name().toLowerCase(Locale.ROOT))){
if(!errorWhenMissing){
@@ -102,6 +85,7 @@ public class BlockStats{
dirty = true;
}
/**Removes a stat, if it exists.*/
public void remove(BlockStat stat){
if(!map.containsKey(stat.category) || !map.get(stat.category).containsKey(stat)){
throw new RuntimeException("No stat entry found: \"" + stat + "\" in block '" + block.name + "'!");

View File

@@ -1,13 +1,12 @@
package io.anuke.mindustry.world.meta;
/**
* A specific category for a stat.
*/
/**A specific category for a stat.*/
public enum StatCategory{
general,
power,
liquids,
items,
crafting,
shooting
shooting,
optional,
}