Merge branches 'master' and 'new-ui' of https://github.com/Anuken/Mindustry

This commit is contained in:
Anuken
2019-07-06 10:13:11 -04:00
129 changed files with 2635 additions and 2351 deletions

View File

@@ -62,7 +62,7 @@ public class Vars{
/** size of UI icons (small)*/
public static final int iconsizesmall = 32;
/** size of UI icons (medium)*/
public static final int iconsizemed = 42;
public static final int iconsizemed = 30;
/** units outside of this bound will simply die instantly */
public static final float finalWorldBounds = worldBounds + 500;
/** ticks spent out of bound until self destruct. */

View File

@@ -5,7 +5,8 @@ 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.*;
import io.anuke.arc.util.Structs;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.game.EventType.TileChangeEvent;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team;
@@ -95,7 +96,7 @@ public class Pathfinder{
*/
private void update(Tile tile, Team team){
//make sure team exists
if(paths != null && paths[team.ordinal()] != null && paths[team.ordinal()].weights != null){
if(paths != null && paths[team.ordinal()] != null && paths[team.ordinal()].weights != null && Structs.inBounds(tile.x, tile.y, paths[team.ordinal()].weights)){
PathData path = paths[team.ordinal()];
if(path.weights[tile.x][tile.y] <= 0.1f){

View File

@@ -13,8 +13,7 @@ import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.game.ContentList;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.defense.*;
import io.anuke.mindustry.world.blocks.defense.turrets.*;
@@ -310,11 +309,11 @@ public class Blocks implements ContentList{
saltRocks = new StaticWall("saltrocks"){{
}};
sporePine = new StaticWall("spore-pine"){{
sporePine = new StaticTree("spore-pine"){{
variants = 0;
}};
pine = new StaticWall("pine"){{
pine = new StaticTree("pine"){{
variants = 0;
}};

View File

@@ -6,26 +6,28 @@ import io.anuke.arc.Graphics.Cursor.SystemCursor;
import io.anuke.arc.freetype.FreeTypeFontGenerator;
import io.anuke.arc.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.Colors;
import io.anuke.arc.graphics.g2d.BitmapFont;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.graphics.g2d.TextureAtlas.AtlasRegion;
import io.anuke.arc.input.KeyCode;
import io.anuke.arc.math.Interpolation;
import io.anuke.arc.scene.*;
import io.anuke.arc.scene.actions.Actions;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.TextField.TextFieldFilter;
import io.anuke.arc.scene.ui.Tooltip.Tooltips;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.editor.MapEditorDialog;
import io.anuke.mindustry.game.EventType.ResizeEvent;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.ui.dialogs.*;
import io.anuke.mindustry.ui.fragments.*;
import static io.anuke.arc.scene.actions.Actions.*;
import static io.anuke.arc.scene.actions.Actions.sequence;
import static io.anuke.mindustry.Vars.*;
public class UI implements ApplicationListener{
@@ -35,9 +37,10 @@ public class UI implements ApplicationListener{
public HudFragment hudfrag;
public ChatFragment chatfrag;
public PlayerListFragment listfrag;
public BackgroundFragment backfrag;
public LoadingFragment loadfrag;
public WidgetGroup menuGroup, hudGroup;
public AboutDialog about;
public GameOverDialog restart;
public CustomGameDialog custom;
@@ -54,7 +57,6 @@ public class UI implements ApplicationListener{
public BansDialog bans;
public AdminsDialog admins;
public TraceDialog traces;
public ChangelogDialog changelog;
public DatabaseDialog database;
public ContentInfoDialog content;
public DeployDialog deploy;
@@ -66,6 +68,7 @@ public class UI implements ApplicationListener{
public UI(){
Skin skin = new Skin(Core.atlas);
generateFonts(skin);
loadExtraStyle(skin);
skin.load(Core.files.internal("sprites/uiskin.json"));
for(BitmapFont font : skin.getAll(BitmapFont.class).values()){
@@ -75,23 +78,8 @@ public class UI implements ApplicationListener{
Core.scene = new Scene(skin);
Core.input.addProcessor(Core.scene);
Dialog.setShowAction(() -> sequence(
alpha(0f),
originCenter(),
moveToAligned(Core.graphics.getWidth() / 2f, Core.graphics.getHeight() / 2f, Align.center),
scaleTo(0.0f, 1f),
parallel(
scaleTo(1f, 1f, 0.1f, Interpolation.fade),
fadeIn(0.1f, Interpolation.fade)
)
));
Dialog.setHideAction(() -> sequence(
parallel(
scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade),
fadeOut(0.1f, Interpolation.fade)
)
));
Dialog.setShowAction(() -> sequence());
Dialog.setHideAction(() -> sequence());
Tooltips.getInstance().animations = false;
@@ -106,6 +94,25 @@ public class UI implements ApplicationListener{
loadCursors();
}
void loadExtraStyle(Skin skin){
AtlasRegion region = Core.atlas.find("flat-down-base");
int[] splits = region.splits;
ScaledNinePatchDrawable copy = new ScaledNinePatchDrawable(new NinePatch(region, splits[0], splits[1], splits[2], splits[3])){
public float getLeftWidth(){ return 0; }
public float getRightWidth(){ return 0; }
public float getTopHeight(){ return 0; }
public float getBottomHeight(){ return 0; }
};
copy.setMinWidth(0);
copy.setMinHeight(0);
copy.setTopHeight(0);
copy.setRightWidth(0);
copy.setBottomHeight(0);
copy.setLeftWidth(0);
skin.add("flat-down", copy, Drawable.class);
}
void loadCursors(){
int cursorScaling = 1, outlineThickness = 3;
Color outlineColor = Color.valueOf("444444");
@@ -143,11 +150,13 @@ public class UI implements ApplicationListener{
@Override
public void init(){
menuGroup = new WidgetGroup();
hudGroup = new WidgetGroup();
menufrag = new MenuFragment();
hudfrag = new HudFragment();
chatfrag = new ChatFragment();
listfrag = new PlayerListFragment();
backfrag = new BackgroundFragment();
loadfrag = new LoadingFragment();
editor = new MapEditorDialog();
@@ -162,7 +171,6 @@ public class UI implements ApplicationListener{
settings = new SettingsMenuDialog();
host = new HostDialog();
paused = new PausedDialog();
changelog = new ChangelogDialog();
about = new AboutDialog();
bans = new BansDialog();
admins = new AdminsDialog();
@@ -175,12 +183,21 @@ public class UI implements ApplicationListener{
Group group = Core.scene.root;
backfrag.build(group);
control.input().getFrag().build(group);
hudfrag.build(group);
menufrag.build(group);
chatfrag.container().build(group);
listfrag.build(group);
menuGroup.setFillParent(true);
menuGroup.touchable(Touchable.childrenOnly);
menuGroup.visible(() -> state.is(State.menu));
hudGroup.setFillParent(true);
hudGroup.touchable(Touchable.childrenOnly);
hudGroup.visible(() -> !state.is(State.menu));
Core.scene.add(menuGroup);
Core.scene.add(hudGroup);
control.input().getFrag().build(hudGroup);
hudfrag.build(hudGroup);
menufrag.build(menuGroup);
chatfrag.container().build(hudGroup);
listfrag.build(hudGroup);
loadfrag.build(group);
}

View File

@@ -9,6 +9,7 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BlockPart;
public enum EditorTool{
zoom,
@@ -107,6 +108,11 @@ public enum EditorTool{
//mode 0 or 1, fill everything with the floor/tile or replace it
if(mode == 0 || mode == -1){
//can't fill parts or multiblocks
if(tile.block() instanceof BlockPart || tile.block().isMultiblock()){
return;
}
Predicate<Tile> tester;
Consumer<Tile> setter;

View File

@@ -15,7 +15,6 @@ import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BlockPart;
import io.anuke.mindustry.world.blocks.Floor;
import static io.anuke.mindustry.Vars.world;
@@ -238,71 +237,6 @@ public class MapEditor{
}
}
public void draw_DEPRECATED(int x, int y, boolean paint, Block drawBlock, double chance){
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
Tile[][] tiles = world.getTiles();
if(drawBlock.isMultiblock()){
x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1);
y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1);
int offsetx = -(drawBlock.size - 1) / 2;
int offsety = -(drawBlock.size - 1) / 2;
for(int dx = 0; dx < drawBlock.size; dx++){
for(int dy = 0; dy < drawBlock.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(Structs.inBounds(worldx, worldy, width(), height())){
Tile tile = tiles[worldx][worldy];
Block block = tile.block();
//bail out if there's anything blocking the way
if(block.isMultiblock() || block instanceof BlockPart){
return;
}
renderer.updatePoint(worldx, worldy);
}
}
}
world.setBlock(tiles[x][y], drawBlock, drawTeam);
}else{
for(int rx = -brushSize; rx <= brushSize; rx++){
for(int ry = -brushSize; ry <= brushSize; ry++){
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
int wx = x + rx, wy = y + ry;
if(wx < 0 || wy < 0 || wx >= width() || wy >= height() || (paint && !isfloor && tiles[wx][wy].block() == Blocks.air)){
continue;
}
Tile tile = tiles[wx][wy];
if(!isfloor && (tile.isLinked() || tile.block().isMultiblock())){
world.removeBlock(tile.link());
}
if(isfloor){
tile.setFloor((Floor)drawBlock);
}else{
tile.setBlock(drawBlock);
if(drawBlock.synthetic()){
tile.setTeam(drawTeam);
}
if(drawBlock.rotate){
tile.rotation((byte)rotation);
}
}
}
}
}
}
}
public MapRenderer renderer(){
return renderer;
}

View File

@@ -263,6 +263,8 @@ 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));
editor.getTags().remove("width");
editor.getTags().remove("height");
player.dead = true;
if(name.isEmpty()){

View File

@@ -286,7 +286,9 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
@Override
public void removed(){
map.remove(tile.pos());
if(tile != null){
map.remove(tile.pos());
}
reset();
}

View File

@@ -47,9 +47,10 @@ public interface BuilderTrait extends Entity, TeamTrait{
buildQueue().clear();
for(BuildRequest request : removal){
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
(!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate)
&& world.tile(request.x, request.y).block() == request.block))){
Tile tile = world.tile(request.x, request.y);
if(!(tile == null || (request.breaking && tile.block() == Blocks.air) ||
(!request.breaking && (tile.rotation() == request.rotation || !request.block.rotate) && tile.block() == request.block))){
buildQueue().addLast(request);
}
}

View File

@@ -41,7 +41,7 @@ public abstract class FlyingUnit extends BaseUnit{
if(target == null){
setState(patrol);
}
};
}
if(target != null){
attack(type.attackLength);

View File

@@ -0,0 +1,302 @@
package io.anuke.mindustry.graphics;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.function.PositionConsumer;
import io.anuke.arc.graphics.Camera;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.graphics.glutils.FrameBuffer;
import io.anuke.arc.math.*;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.util.*;
import io.anuke.arc.util.noise.RidgedPerlin;
import io.anuke.arc.util.noise.Simplex;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.type.UnitType;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.blocks.OreBlock;
import static io.anuke.mindustry.Vars.*;
public class MenuRenderer implements Disposable{
private static final float darkness = 0.3f;
private final int width = !mobile ? 100 : 60, height = !mobile ? 50 : 40;
private int cacheFloor, cacheWall;
private Camera camera = new Camera();
private Matrix3 mat = new Matrix3();
private FrameBuffer shadows;
private CacheBatch batch;
private float time = 0f;
private float flyerRot = 45f;
private int flyers = Mathf.chance(0.2) ? Mathf.random(30) : Mathf.random(12);
private UnitType flyerType = Structs.select(UnitTypes.wraith, UnitTypes.wraith, UnitTypes.ghoul, UnitTypes.phantom, UnitTypes.phantom, UnitTypes.revenant);
public MenuRenderer(){
Time.mark();
generate();
cache();
Log.info("Time to generate menu: {0}", Time.elapsed());
}
private void generate(){
Tile[][] tiles = world.createTiles(width, height);
Array<Block> ores = content.blocks().select(b -> b instanceof OreBlock);
shadows = new FrameBuffer(width, height);
int offset = Mathf.random(100000);
Simplex s1 = new Simplex(offset);
Simplex s2 = new Simplex(offset + 1);
Simplex s3 = new Simplex(offset + 2);
RidgedPerlin rid = new RidgedPerlin(1 + offset, 1);
Block[] selected = Structs.select(
new Block[]{Blocks.sand, Blocks.sandRocks},
new Block[]{Blocks.shale, Blocks.shaleRocks},
new Block[]{Blocks.ice, Blocks.icerocks},
new Block[]{Blocks.sand, Blocks.sandRocks},
new Block[]{Blocks.shale, Blocks.shaleRocks},
new Block[]{Blocks.ice, Blocks.icerocks},
new Block[]{Blocks.moss, Blocks.sporePine}
);
Block[] selected2 = Structs.select(
new Block[]{Blocks.ignarock, Blocks.duneRocks},
new Block[]{Blocks.ignarock, Blocks.duneRocks},
new Block[]{Blocks.stone, Blocks.rocks},
new Block[]{Blocks.stone, Blocks.rocks},
new Block[]{Blocks.moss, Blocks.sporerocks},
new Block[]{Blocks.salt, Blocks.saltRocks}
);
Block ore1 = ores.random();
ores.remove(ore1);
Block ore2 = ores.random();
double tr1 = Mathf.random(0.65f, 0.85f);
double tr2 = Mathf.random(0.65f, 0.85f);
boolean doheat = Mathf.chance(0.25);
boolean tendrils = Mathf.chance(0.25);
boolean tech = Mathf.chance(0.25);
int secSize = 10;
Block floord = selected[0], walld = selected[1];
Block floord2 = selected2[0], walld2 = selected2[1];
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Block floor = floord;
Block ore = Blocks.air;
Block wall = Blocks.air;
if(s1.octaveNoise2D(3, 0.5, 1/20.0, x, y) > 0.5){
wall = walld;
}
if(s3.octaveNoise2D(3, 0.5, 1/20.0, x, y) > 0.5){
floor = floord2;
if(wall != Blocks.air){
wall = walld2;
}
}
if(s2.octaveNoise2D(3, 0.3, 1/30.0, x, y) > tr1){
ore = ore1;
}
if(s2.octaveNoise2D(2, 0.2, 1/15.0, x, y+99999) > tr2){
ore = ore2;
}
if(doheat){
double heat = s3.octaveNoise2D(4, 0.6, 1 / 50.0, x, y + 9999);
double base = 0.65;
if(heat > base){
ore = Blocks.air;
wall = Blocks.air;
floor = Blocks.ignarock;
if(heat > base + 0.1){
floor = Blocks.hotrock;
if(heat > base + 0.15){
floor = Blocks.magmarock;
}
}
}
}
if(tech){
int mx = x % secSize, my = y % secSize;
int sclx = x / secSize, scly = y / secSize;
if(s1.octaveNoise2D(2, 1f / 10f, 0.5f, sclx, scly) > 0.4f && (mx == 0 || my == 0 || mx == secSize - 1 || my == secSize - 1)){
floor = Blocks.darkPanel3;
if(Mathf.dst(mx, my, secSize/2, secSize/2) > secSize/2f + 1){
floor = Blocks.darkPanel4;
}
if(wall != Blocks.air && Mathf.chance(0.7)){
wall = Blocks.darkMetal;
}
}
}
if(tendrils){
if(rid.getValue(x, y, 1f / 17f) > 0f){
floor = Mathf.chance(0.2) ? Blocks.sporeMoss : Blocks.moss;
if(wall != Blocks.air){
wall = Blocks.sporerocks;
}
}
}
Tile tile;
tiles[x][y] = (tile = new CachedTile());
tile.x = (short)x;
tile.y = (short)y;
tile.setFloor((Floor) floor);
tile.setBlock(wall);
tile.setOverlay(ore);
}
}
}
private void cache(){
//draw shadows
Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight());
shadows.beginDraw(Color.CLEAR);
Draw.color(Color.BLACK);
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
if(world.rawTile(x, y).block() != Blocks.air){
Fill.rect(x + 0.5f, y + 0.5f, 1, 1);
}
}
}
Draw.color();
shadows.endDraw();
SpriteBatch prev = Core.batch;
Core.batch = batch = new CacheBatch(new SpriteCache(width * height * 6, false));
batch.beginCache();
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Tile tile = world.rawTile(x, y);
tile.floor().draw(tile);
}
}
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Tile tile = world.rawTile(x, y);
if(tile.overlay() != Blocks.air){
tile.overlay().draw(tile);
}
}
}
cacheFloor = batch.endCache();
batch.beginCache();
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Tile tile = world.rawTile(x, y);
if(tile.block() != Blocks.air){
tile.block().draw(tile);
}
}
}
//Draw.rect("error", world.width() * tilesize/2f, world.height() * tilesize/2f, 100f, 100f);
cacheWall = batch.endCache();
Core.batch = prev;
}
public void render(){
time += Time.delta();
float scaling = Math.max(Unit.dp.scl(4f), Math.max(Core.graphics.getWidth() / ((width - 1f) * tilesize), Core.graphics.getHeight() / ((height - 1f) * tilesize)));
camera.position.set(width * tilesize / 2f, height * tilesize / 2f);
camera.resize(Core.graphics.getWidth() / scaling,
Core.graphics.getHeight() / scaling);
mat.set(Draw.proj());
Draw.flush();
Draw.proj(camera.projection());
batch.setProjection(camera.projection());
batch.beginDraw();
batch.drawCache(cacheFloor);
batch.endDraw();
Draw.rect(Draw.wrap(shadows.getTexture()),
width * tilesize / 2f - 4f, height * tilesize / 2f - 4f,
width * tilesize, -height * tilesize);
Draw.flush();
batch.beginDraw();
batch.drawCache(cacheWall);
batch.endDraw();
drawFlyers();
Draw.proj(mat);
Draw.color(0f, 0f, 0f, darkness);
Fill.crect(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight());
Draw.color();
}
private void drawFlyers(){
Draw.color(0f, 0f, 0f, 0.4f);
float size = Math.max(flyerType.iconRegion.getWidth(), flyerType.iconRegion.getHeight()) * Draw.scl * 1.6f;
flyers((x, y) -> {
Draw.rect(flyerType.region, x - 12f, y - 13f, flyerRot - 90);
});
flyers((x, y) -> {
Draw.rect("circle-shadow", x, y, size, size);
});
Draw.color();
flyers((x, y) -> {
float engineOffset = flyerType.engineOffset, engineSize = flyerType.engineSize, rotation = flyerRot;
Draw.color(Pal.engine);
Fill.circle(x + Angles.trnsx(rotation + 180, engineOffset), y + Angles.trnsy(rotation + 180, engineOffset),
engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f));
Draw.color(Color.WHITE);
Fill.circle(x + Angles.trnsx(rotation + 180, engineOffset - 1f), y + Angles.trnsy(rotation + 180, engineOffset - 1f),
(engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f)) / 2f);
Draw.color();
Draw.rect(flyerType.region, x, y, flyerRot - 90);
});
}
private void flyers(PositionConsumer cons){
float tw = width * tilesize * 2;
float th = height * tilesize * 2;
float range = 500f;
float offset = -600f;
for(int i = 0; i < flyers; i++){
Tmp.v1.trns(flyerRot, time * (2.5f + flyerType.speed));
cons.accept((Mathf.randomSeedRange(i, range) + Tmp.v1.x + Mathf.absin(time + Mathf.randomSeedRange(i + 2, 500), 10f, 3.4f) + offset) % tw,
(Mathf.randomSeedRange(i + 1, range) + Tmp.v1.y + Mathf.absin(time + Mathf.randomSeedRange(i + 3, 500), 10f, 3.4f) + offset) % th);
}
}
@Override
public void dispose(){
batch.dispose();
shadows.dispose();
}
}

View File

@@ -129,6 +129,7 @@ public class MinimapRenderer implements Disposable{
}
private int colorFor(Tile tile){
if(tile == null) return 0;
tile = tile.link();
return MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam());
}

View File

@@ -52,7 +52,7 @@ public class Pal{
bar = Color.SLATE,
accent = Color.valueOf("ffd37f"),
stat = Color.valueOf("ffd37f"),
locked = Color.valueOf("989aa4"),
gray = Color.valueOf("454545"),
accentBack = Color.valueOf("d4816b"),
place = Color.valueOf("6335f8"),
remove = Color.valueOf("e55454"),

View File

@@ -42,7 +42,7 @@ public abstract class InputHandler implements InputProcessor{
/** Distance on the back from where items originate. */
final static float backTrns = 3f;
public final OverlayFragment frag = new OverlayFragment(this);
public final OverlayFragment frag = new OverlayFragment();
public Block block;
public int rotation;

View File

@@ -261,7 +261,7 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override
public void buildUI(Table table){
table.addImage("blank").color(Pal.accent).height(3f).colspan(4).growX();
table.addImage("whiteui").color(Pal.gray).height(4f).colspan(4).growX();
table.row();
table.left().margin(0f).defaults().size(48f);

View File

@@ -1,54 +0,0 @@
package io.anuke.mindustry.io;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.util.serialization.JsonReader;
import io.anuke.arc.util.serialization.JsonValue;
import static io.anuke.mindustry.Vars.releasesURL;
public class Changelogs{
public static void getChangelog(Consumer<Array<VersionInfo>> success, Consumer<Throwable> fail){
Core.net.httpGet(releasesURL, result -> {
JsonReader reader = new JsonReader();
JsonValue value = reader.parse(result.getResultAsString()).child;
Array<VersionInfo> out = new Array<>();
while(value != null){
String name = value.getString("name");
String description = value.getString("body").replace("\r", "");
int id = value.getInt("id");
int build = Integer.parseInt(value.getString("tag_name").substring(1));
out.add(new VersionInfo(name, description, id, build, value.getString("published_at")));
value = value.next;
}
success.accept(out);
}, fail);
}
public static class VersionInfo{
public final String name, description, date;
public final int id, build;
public VersionInfo(String name, String description, int id, int build, String date){
this.name = name;
this.description = description;
this.id = id;
this.build = build;
this.date = date;
}
@Override
public String toString(){
return "VersionInfo{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", id=" + id +
", build=" + build +
'}';
}
}
}

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.io;
import io.anuke.arc.collection.*;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.Time;
import io.anuke.arc.util.io.CounterInputStream;
import io.anuke.mindustry.entities.Entities;
@@ -253,7 +254,6 @@ public abstract class SaveVersion extends SaveFileReader{
}
public void readContentHeader(DataInput stream) throws IOException{
byte mapped = stream.readByte();
MappableContent[][] map = new MappableContent[ContentType.values().length][0];

View File

@@ -69,7 +69,7 @@ public class Item extends UnlockableContent implements Comparable<Item>{
@Override
public TextureRegion getContentIcon(){
return icon(Icon.xxlarge);
return icon(Icon.large);
}
@Override

View File

@@ -65,11 +65,8 @@ public class UnitType extends UnlockableContent{
weapon.load();
iconRegion = Core.atlas.find("unit-icon-" + name, Core.atlas.find(name));
region = Core.atlas.find(name);
if(!isFlying){
legRegion = Core.atlas.find(name + "-leg");
baseRegion = Core.atlas.find(name + "-base");
}
legRegion = Core.atlas.find(name + "-leg");
baseRegion = Core.atlas.find(name + "-base");
}
@Override

View File

@@ -26,7 +26,7 @@ public class ItemsDisplay extends Table{
top().left();
margin(0);
table("flat", t -> {
table("button", t -> {
t.margin(10).marginLeft(15).marginTop(15f);
t.add("$launcheditems").colspan(3).left().padBottom(5);
t.row();

View File

@@ -2,19 +2,22 @@ package io.anuke.mindustry.ui;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color;
import io.anuke.mindustry.graphics.Pal;
public class Links{
private static LinkEntry[] links;
private static void createLinks(){
links = new LinkEntry[]{
new LinkEntry("discord", "https://discord.gg/mindustry", Color.valueOf("7289da")),
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")),
new LinkEntry("wiki", "https://mindustrygame.github.io/wiki/", Color.valueOf("0f142f")),
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")),
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")),
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")),
new LinkEntry("dev-builds", "https://jenkins.hellomouse.net/job/mindustry/", Color.valueOf("fafbfc"))
new LinkEntry("discord", "https://discord.gg/mindustry", Color.valueOf("7289da")),
new LinkEntry("changelog", "https://github.com/Anuken/Mindustry/releases", Pal.accent.cpy()),
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")),
new LinkEntry("wiki", "https://mindustrygame.github.io/wiki/", Color.valueOf("0f142f")),
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")),
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")),
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")),
new LinkEntry("dev-builds", "https://jenkins.hellomouse.net/job/mindustry/", Color.valueOf("fafbfc"))
};
}

View File

@@ -80,10 +80,6 @@ public class AboutDialog extends FloatingDialog{
buttons.addButton("$credits", this::showCredits).size(200f, 64f);
if(!ios && !OS.isMac){
buttons.addButton("$changelog.title", ui.changelog::show).size(200f, 64f);
}
if(Core.graphics.isPortrait()){
for(Cell<?> cell : buttons.getCells()){
cell.width(140f);
@@ -98,7 +94,7 @@ public class AboutDialog extends FloatingDialog{
dialog.cont.add("$credits.text");
dialog.cont.row();
if(!contributors.isEmpty()){
dialog.cont.addImage("blank").color(Pal.accent).fillX().height(3f).pad(3f);
dialog.cont.addImage("whiteui").color(Pal.accent).fillX().height(3f).pad(3f);
dialog.cont.row();
dialog.cont.add("$contributors");
dialog.cont.row();

View File

@@ -1,89 +0,0 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.scene.ui.ScrollPane;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.OS;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.io.Changelogs;
import io.anuke.mindustry.io.Changelogs.VersionInfo;
import static io.anuke.mindustry.Vars.ios;
public class ChangelogDialog extends FloatingDialog{
private final float vw = 600;
private Array<VersionInfo> versions;
public ChangelogDialog(){
super("$changelog.title");
addCloseButton();
cont.add("$changelog.loading");
shown(() -> {
if(!ios && !OS.isMac){
Changelogs.getChangelog(result -> {
versions = result;
Core.app.post(this::setup);
}, t -> {
Log.err(t);
Core.app.post(this::setup);
});
}
});
}
void setup(){
Table table = new Table();
ScrollPane pane = new ScrollPane(table);
cont.clear();
cont.add(pane).grow();
if(versions == null){
table.add("$changelog.error");
if(Vars.android){
table.row();
table.add("$changelog.error.android").padTop(8);
}
if(ios){
table.row();
table.add("$changelog.error.ios").padTop(8);
}
}else{
for(VersionInfo info : versions){
String desc = info.description;
desc = desc.replace("Android", "Mobile");
Table in = new Table("underline");
in.top().left().margin(10);
in.add("[accent]" + info.name + "[LIGHT_GRAY] | " + info.date);
if(info.build == Version.build){
in.row();
in.add("$changelog.current");
}else if(info == versions.first()){
in.row();
in.add("$changelog.latest");
}
in.row();
in.labelWrap("[lightgray]" + desc).width(vw - 20).padTop(12);
table.add(in).width(vw).pad(8).row();
}
int lastid = Core.settings.getInt("lastBuild");
if(lastid != 0 && versions.peek().build > lastid){
Core.settings.put("lastBuild", versions.peek().build);
Core.settings.save();
show();
}
}
}
}

View File

@@ -2,9 +2,12 @@ package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.scene.event.ClickListener;
import io.anuke.arc.scene.event.HandCursorListener;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.Content;
@@ -46,16 +49,20 @@ public class DatabaseDialog extends FloatingDialog{
list.left();
int maxWidth = Core.graphics.isPortrait() ? 7 : 13;
float size = Vars.iconsize;
int count = 0;
for(int i = 0; i < array.size; i++){
UnlockableContent unlock = (UnlockableContent)array.get(i);
Image image = unlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image("icon-locked");
Image image = unlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image("icon-locked", Pal.gray);
image.addListener(new HandCursorListener());
list.add(image).size(size).pad(3);
list.add(image).size(unlocked(unlock) ? 8*4 : Vars.iconsize).pad(3);
ClickListener listener = new ClickListener();
image.addListener(listener);
if(!Vars.mobile){
image.update(() -> image.getColor().lerp(!listener.isOver() ? Color.LIGHT_GRAY : Color.WHITE, 0.4f * Time.delta()));
}
if(unlocked(unlock)){
image.clicked(() -> Vars.ui.content.show(unlock));

View File

@@ -8,8 +8,7 @@ import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.Lines;
import io.anuke.arc.scene.Group;
import io.anuke.arc.scene.ui.TextButton;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.Align;
import io.anuke.arc.util.Structs;
import io.anuke.mindustry.content.Zones;
@@ -57,48 +56,53 @@ public class DeployDialog extends FloatingDialog{
Core.settings.save();
}
cont.stack(control.saves.getZoneSlot() == null ? new View() : new Table(){{
SaveSlot slot = control.saves.getZoneSlot();
Stack stack = new Stack();
TextButton[] b = {null};
if(control.saves.getZoneSlot() != null){
stack.add(new Table(t -> {
SaveSlot slot = control.saves.getZoneSlot();
TextButton button = addButton(Core.bundle.format("resume", slot.getZone().localizedName()), () -> {
if(b[0].childrenPressed()) return;
TextButton button = t.addButton(Core.bundle.format("resume", slot.getZone().localizedName()), () -> {
hide();
ui.loadAnd(() -> {
try{
control.saves.getZoneSlot().load();
state.set(State.playing);
}catch(SaveException e){ //make sure to handle any save load errors!
e.printStackTrace();
if(control.saves.getZoneSlot() != null) control.saves.getZoneSlot().delete();
Core.app.post(() -> ui.showInfo("$save.corrupted"));
show();
}
});
}).size(230f).get();
b[0] = button;
hide();
ui.loadAnd(() -> {
try{
control.saves.getZoneSlot().load();
state.set(State.playing);
}catch(SaveException e){ //make sure to handle any save load errors!
e.printStackTrace();
if(control.saves.getZoneSlot() != null) control.saves.getZoneSlot().delete();
Core.app.post(() -> ui.showInfo("$save.corrupted"));
show();
}
});
}).size(230f).get();
String color = "[lightgray]";
String color = "[lightgray]";
button.defaults().colspan(2);
button.row();
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
button.row();
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
button.row();
button.add().grow();
button.row();
button.defaults().colspan(2);
button.row();
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
button.row();
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
button.row();
button.addButton("$abandon", () -> {
ui.showConfirm("$warning", "$abandon.text", () -> {
slot.delete();
setup();
});
}).growX().height(50f).pad(-12).padTop(10);
t.row();
}}, new ItemsDisplay()).grow();
t.addButton("$abandon", () -> {
ui.showConfirm("$warning", "$abandon.text", () -> {
slot.delete();
setup();
});
}).width(230f).height(50f).padTop(3);
}));
}else{
stack.add(new View());
}
stack.add(new ItemsDisplay());
cont.add(stack).grow();
//set up direct and indirect children
for(ZoneNode node : nodes){
@@ -169,7 +173,7 @@ public class DeployDialog extends FloatingDialog{
for(ZoneNode node : nodes){
for(ZoneNode child : node.allChildren){
Lines.stroke(Unit.dp.scl(3f), node.zone.locked() || child.zone.locked() ? Pal.locked : Pal.accent);
Lines.stroke(Unit.dp.scl(3f), node.zone.locked() || child.zone.locked() ? Pal.gray : Pal.accent);
Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
}
}

View File

@@ -29,7 +29,7 @@ public class LanguageDialog extends FloatingDialog{
ButtonGroup<TextButton> group = new ButtonGroup<>();
for(Locale loc : locales){
TextButton button = new TextButton(Strings.capitalize(loc.getDisplayName(loc)), "toggle");
TextButton button = new TextButton(Strings.capitalize(loc.getDisplayName(loc)), "clear-toggle");
button.clicked(() -> {
if(getLocale().equals(loc)) return;
Core.settings.put("locale", loc.toString());
@@ -37,7 +37,7 @@ public class LanguageDialog extends FloatingDialog{
Log.info("Setting locale: {0}", loc.toString());
ui.showInfo("$language.restart");
});
langs.add(button).group(group).update(t -> t.setChecked(loc.equals(getLocale()))).size(400f, 50f).pad(2).row();
langs.add(button).group(group).update(t -> t.setChecked(loc.equals(getLocale()))).size(400f, 50f).row();
}
cont.add(pane);

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.input.KeyCode;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Table;
@@ -20,8 +21,43 @@ public class MapsDialog extends FloatingDialog{
public MapsDialog(){
super("$maps");
addCloseButton();
buttons.addImageTextButton("$editor.importmap", "icon-add", iconsize, () -> {
buttons.remove();
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
Core.app.post(this::hide);
}
});
shown(this::setup);
onResize(() -> {
if(dialog != null){
dialog.hide();
}
setup();
});
}
void setup(){
buttons.clearChildren();
if(Core.graphics.isPortrait()){
buttons.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f*2f, 64f).colspan(2);
buttons.row();
}else{
buttons.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f, 64f);
}
buttons.addImageTextButton("$editor.newmap", "icon-add", iconsize, () -> {
ui.showTextInput("$editor.newmap", "$name", "", text -> {
ui.loadAnd(() -> {
ui.editor.show();
ui.editor.editor.getTags().put("name", text);
});
});
}).size(210f, 64f);
buttons.addImageTextButton("$editor.importmap", "icon-load", iconsize, () -> {
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
world.maps.tryCatchMapError(() -> {
if(MapIO.isImage(file)){
@@ -60,17 +96,8 @@ public class MapsDialog extends FloatingDialog{
});
}, true, FileChooser.anyMapFiles);
}).size(230f, 64f);
}).size(210f, 64f);
shown(this::setup);
onResize(() -> {
if(dialog != null){
dialog.hide();
}
});
}
void setup(){
cont.clear();
Table maps = new Table();
@@ -107,6 +134,8 @@ public class MapsDialog extends FloatingDialog{
maps.add("$maps.none");
}
cont.add(buttons).growX();
cont.row();
cont.add(pane).uniformX();
}

View File

@@ -43,6 +43,8 @@ public class SettingsMenuDialog extends SettingsDialog{
wasPaused = state.is(State.paused);
state.set(State.paused);
}
rebuildMenu();
});
setFillParent(true);
@@ -54,7 +56,7 @@ public class SettingsMenuDialog extends SettingsDialog{
cont.remove();
buttons.remove();
menu = new Table();
menu = new Table("button");
Consumer<SettingsTable> s = table -> {
table.row();
@@ -69,16 +71,7 @@ public class SettingsMenuDialog extends SettingsDialog{
prefs.top();
prefs.margin(14f);
menu.defaults().size(300f, 60f).pad(3f);
menu.addButton("$settings.game", () -> visible(0));
menu.row();
menu.addButton("$settings.graphics", () -> visible(1));
menu.row();
menu.addButton("$settings.sound", () -> visible(2));
menu.row();
menu.addButton("$settings.language", ui.language::show);
menu.row();
menu.addButton("$settings.controls", ui.controls::show).visible(() -> !mobile || Core.settings.getBool("keyboard"));
rebuildMenu();
prefs.clearChildren();
prefs.add(menu);
@@ -114,6 +107,25 @@ public class SettingsMenuDialog extends SettingsDialog{
addSettings();
}
void rebuildMenu(){
menu.clearChildren();
String style = "clear";
menu.defaults().size(300f, 60f);
menu.addButton("$settings.game", style, () -> visible(0));
menu.row();
menu.addButton("$settings.graphics", style, () -> visible(1));
menu.row();
menu.addButton("$settings.sound", style, () -> visible(2));
menu.row();
menu.addButton("$settings.language", style, ui.language::show);
if(!mobile || Core.settings.getBool("keyboard")){
menu.row();
menu.addButton("$settings.controls", style, ui.controls::show);
}
}
void addSettings(){
//TODO add when sound works again
//sound.volumePrefs();
@@ -237,6 +249,7 @@ public class SettingsMenuDialog extends SettingsDialog{
}
private void back(){
rebuildMenu();
prefs.clearChildren();
prefs.add(menu);
}

View File

@@ -192,7 +192,7 @@ public class TechTreeDialog extends FloatingDialog{
button.update(() -> {
float offset = (Core.graphics.getHeight() % 2) / 2f;
button.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f + offset, Align.center);
button.getStyle().up = Core.scene.skin.getDrawable(!locked(node.node) ? "content-background" : !data.hasItems(node.node.requirements) ? "content-background-noitems" : "content-background-locked");
button.getStyle().up = Core.scene.skin.getDrawable(!locked(node.node) ? "button-over" : !data.hasItems(node.node.requirements) ? "button-red" : "button");
((TextureRegionDrawable)button.getStyle().imageUp)
.setRegion(node.visible ? node.node.block.icon(Icon.medium) : Core.atlas.find("icon-locked"));
button.getImage().setColor(!locked(node.node) ? Color.WHITE : Color.GRAY);
@@ -249,11 +249,12 @@ public class TechTreeDialog extends FloatingDialog{
infoTable.update(() -> infoTable.setPosition(button.getX() + button.getWidth(), button.getY() + button.getHeight(), Align.topLeft));
infoTable.left();
infoTable.background("button").margin(8f);
infoTable.table("content-background", b -> {
infoTable.table(b -> {
b.margin(0).left().defaults().left();
b.addImageButton("icon-info", "node", iconsize, () -> ui.content.show(node.block)).growY().width(50f);
b.addImageButton("icon-info-small", "clear", iconsizesmall, () -> ui.content.show(node.block)).growY().width(50f);
b.add().grow();
b.table(desc -> {
desc.left().defaults().left();
@@ -280,14 +281,14 @@ public class TechTreeDialog extends FloatingDialog{
if(mobile && locked(node)){
b.row();
b.addImageTextButton("$research", "icon-check", "node", iconsize, () -> unlock(node))
b.addImageTextButton("$research", "icon-check-small", "node", iconsizesmall, () -> unlock(node))
.disabled(i -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3);
}
});
infoTable.row();
if(node.block.description != null){
infoTable.table("dialogDim", t -> t.margin(3f).left().labelWrap(node.block.description).color(Color.LIGHT_GRAY).growX()).fillX();
infoTable.table(t -> t.margin(3f).left().labelWrap(node.block.description).color(Color.LIGHT_GRAY).growX()).fillX();
}
@@ -305,7 +306,7 @@ public class TechTreeDialog extends FloatingDialog{
for(TechTreeNode child : node.children){
if(!child.visible) continue;
Lines.stroke(Unit.dp.scl(3f), locked(node.node) || locked(child.node) ? Pal.locked : Pal.accent);
Lines.stroke(Unit.dp.scl(4f), locked(node.node) || locked(child.node) ? Pal.gray : Pal.accent);
Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
}
}

View File

@@ -1,33 +0,0 @@
package io.anuke.mindustry.ui.fragments;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.scene.Group;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.graphics.Shaders;
import static io.anuke.mindustry.Vars.state;
public class BackgroundFragment extends Fragment{
@Override
public void build(Group parent){
Core.scene.table().addRect((a, b, w, h) -> {
Draw.colorl(0.1f);
Fill.crect(0, 0, w, h);
Draw.shader(Shaders.menu);
Fill.crect(0, 0, w, h);
Draw.shader();
boolean portrait = Core.graphics.getWidth() < Core.graphics.getHeight();
float logoscl = (int)Unit.dp.scl(1);
TextureRegion logo = Core.atlas.find("logotext");
float logow = logo.getWidth() * logoscl;
float logoh = logo.getHeight() * logoscl;
Draw.color();
Draw.rect(logo, (int)(w / 2), (int)(h - 10 - logoh - Unit.dp.scl(portrait ? 30f : 0)) + logoh / 2, logow, logoh);
}).visible(() -> state.is(State.menu)).grow();
}
}

View File

@@ -24,6 +24,19 @@ public class BlockConfigFragment extends Fragment{
public void build(Group parent){
table.visible(false);
parent.addChild(table);
//hacky way to hide block config when in menu
//TODO remove?
Core.scene.add(new Element(){
@Override
public void act(float delta){
super.act(delta);
if(state.is(State.menu)){
table.visible(false);
configTile = null;
}
}
});
}
public boolean isShown(){
@@ -47,11 +60,6 @@ public class BlockConfigFragment extends Fragment{
Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out));
table.update(() -> {
if(state.is(State.menu)){
hideConfig();
return;
}
if(configTile != null && configTile.block().shouldHideConfigure(configTile, player)){
hideConfig();
return;

View File

@@ -52,7 +52,6 @@ public class BlockInventoryFragment extends Fragment{
@Override
public void build(Group parent){
table = new Table();
table.visible(() -> !state.is(State.menu));
table.setTransform(true);
parent.setTransform(true);
parent.addChild(table);

View File

@@ -15,14 +15,14 @@ import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.util.Align;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.input.Binding;
import io.anuke.mindustry.net.Net;
import static io.anuke.arc.Core.input;
import static io.anuke.arc.Core.scene;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.maxTextLength;
import static io.anuke.mindustry.Vars.mobile;
public class ChatFragment extends Table{
private final static int messagesShown = 10;
@@ -61,7 +61,7 @@ public class ChatFragment extends Table{
}
}
return !state.is(State.menu) && Net.active();
return Net.active();
});
update(() -> {

View File

@@ -58,21 +58,22 @@ public class HudFragment extends Fragment{
//menu at top left
parent.fill(cont -> {
cont.top().left().visible(() -> !state.is(State.menu));
cont.top().left();
if(mobile){
{
Table select = new Table();
select.visible(() -> !state.is(State.menu));
select.left();
select.defaults().size(dsize).left();
select.addImageButton("icon-menu-large", "clear", iconsize, ui.paused::show);
flip = select.addImageButton("icon-arrow-up", "clear", iconsize, this::toggleMenus).get();
String style = "clear-trans";
select.addImageButton("icon-pause", "clear", iconsize, () -> {
select.addImageButton("icon-menu-large", style, iconsize, ui.paused::show);
flip = select.addImageButton("icon-arrow-up", style, iconsize, this::toggleMenus).get();
select.addImageButton("icon-pause", style, iconsize, () -> {
if(Net.active()){
ui.listfrag.toggle();
}else{
@@ -87,7 +88,7 @@ public class HudFragment extends Fragment{
}
}).get();
select.addImageButton("icon-settings", "clear", iconsize, () -> {
select.addImageButton("icon-settings", style, iconsize, () -> {
if(Net.active() && mobile){
if(ui.chatfrag.chatOpen()){
ui.chatfrag.hide();
@@ -107,7 +108,7 @@ public class HudFragment extends Fragment{
}
}).get();
select.addImage("blank").color(Pal.accent).width(3f).fillY();
select.addImage("whiteui").color(Pal.gray).width(4f).fillY();
float size = Unit.dp.scl(dsize);
Array<Element> children = new Array<>(select.getChildren());
@@ -116,15 +117,15 @@ public class HudFragment extends Fragment{
int index = 0;
for(Element elem : children){
int fi = index++;
Core.scene.add(elem);
parent.addChild(elem);
elem.visible(() -> {
if(fi < 4){
elem.setSize(size);
}else{
elem.setSize(Unit.dp.scl(3f), size);
elem.setSize(Unit.dp.scl(4f), size);
}
elem.setPosition(fi * size, Core.graphics.getHeight(), Align.topLeft);
return !state.is(State.menu);
return true;
});
}
@@ -132,7 +133,7 @@ public class HudFragment extends Fragment{
}
cont.row();
cont.addImage("blank").height(3f).color(Pal.accent).fillX();
cont.addImage("whiteui").height(4f).color(Pal.gray).fillX();
cont.row();
}
@@ -165,7 +166,7 @@ public class HudFragment extends Fragment{
addWaveTable(waves);
addPlayButton(btable);
wavesMain.add(stack).width(dsize * 4 + 3f);
wavesMain.add(stack).width(dsize * 4 + 4f);
wavesMain.row();
wavesMain.table("button", t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.WHITE))
.grow()).fillX().visible(() -> state.rules.waves && state.boss() != null).height(60f).get();
@@ -215,9 +216,7 @@ public class HudFragment extends Fragment{
float[] position = {0, 0};
t.row();
t.addImageTextButton("$editor.removeunit", "icon-quit", "toggle", iconsize, () -> {
}).fillX().update(b -> {
t.addImageTextButton("$editor.removeunit", "icon-quit", "toggle", iconsize, () -> {}).fillX().update(b -> {
boolean[] found = {false};
if(b.isChecked()){
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
@@ -247,7 +246,7 @@ public class HudFragment extends Fragment{
}
});
}
}).width(dsize * 4 + 3f);
}).width(dsize * 4 + 4f);
editorMain.visible(() -> shown && state.isEditor());
}
@@ -265,12 +264,11 @@ public class HudFragment extends Fragment{
});
//minimap
parent.fill(t -> t.top().right().add(new Minimap()).visible(() -> !state.is(State.menu) && Core.settings.getBool("minimap")));
parent.fill(t -> t.top().right().add(new Minimap()).visible(() -> Core.settings.getBool("minimap")));
//spawner warning
parent.fill(t -> {
t.touchable(Touchable.disabled);
t.visible(() -> !state.is(State.menu));
t.table("flat", c -> c.add("$nearpoint")
.update(l -> l.setColor(Tmp.c1.set(Color.WHITE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 10f, 1f))))
.get().setAlignment(Align.center, Align.center))
@@ -278,7 +276,7 @@ public class HudFragment extends Fragment{
});
parent.fill(t -> {
t.visible(() -> netServer.isWaitingForPlayers() && !state.is(State.menu));
t.visible(() -> netServer.isWaitingForPlayers());
t.table("button", c -> c.add("$waiting.players"));
});
@@ -331,7 +329,7 @@ public class HudFragment extends Fragment{
//launch button
parent.fill(t -> {
t.top().right().visible(() -> !state.is(State.menu));
t.top().right();
TextButton[] testb = {null};
TextButton button = Elements.newButton("$launch", () -> {
FloatingDialog dialog = new FloatingDialog("$launch");
@@ -390,11 +388,11 @@ public class HudFragment extends Fragment{
//'saving' indicator
parent.fill(t -> {
t.bottom().visible(() -> !state.is(State.menu) && control.saves.isSaving());
t.bottom().visible(() -> control.saves.isSaving());
t.add("$saveload");
});
blockfrag.build(Core.scene.root);
blockfrag.build(parent);
}
@Remote(targets = Loc.both, forward = true, called = Loc.both)

View File

@@ -2,30 +2,45 @@ package io.anuke.mindustry.ui.fragments;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.Texture;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.math.Interpolation;
import io.anuke.arc.scene.Group;
import io.anuke.arc.scene.actions.Actions;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.ui.Button;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Strings;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.util.Align;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.EventType.ResizeEvent;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.ui.MenuButton;
import io.anuke.mindustry.graphics.MenuRenderer;
import io.anuke.mindustry.ui.MobileButton;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import static io.anuke.mindustry.Vars.*;
public class MenuFragment extends Fragment{
private Table container;
private Texture logo = new Texture("sprites/logo.png");
private Table container, submenu;
private Button currentMenu;
private MenuRenderer renderer;
@Override
public void build(Group parent){
renderer = new MenuRenderer();
parent.fill((x, y, w, h) -> {
renderer.render();
});
parent.fill(c -> {
container = c;
container.visible(() -> state.is(State.menu));
if(!mobile){
buildDesktop();
Events.on(ResizeEvent.class, event -> buildDesktop());
}else{
buildMobile();
Events.on(ResizeEvent.class, event -> buildMobile());
@@ -33,19 +48,29 @@ public class MenuFragment extends Fragment{
});
//discord icon in top right
parent.fill(c -> c.top().right().addButton("", "discord", ui.discord::show).size(84, 45)
.visible(() -> state.is(State.menu)));
//parent.fill(c -> c.top().right().addButton("", "discord", ui.discord::show).size(84, 45)
//.visible(() -> state.is(State.menu)));
//info icon
if(mobile){
parent.fill(c -> c.top().left().addButton("", "info", ui.about::show).size(84, 45)
.visible(() -> state.is(State.menu)));
parent.fill(c -> c.bottom().left().addButton("", "info", ui.about::show).size(84, 45));
}
//version info
parent.fill(c -> c.bottom().left().add(Strings.format("Mindustry v{0} {1}-{2} {3}{4}", Version.number, Version.modifier, Version.type,
(Version.build == -1 ? "custom build" : "build " + Version.build), Version.revision == 0 ? "" : "." + Version.revision))
.visible(() -> state.is(State.menu)));
String versionText = "[#ffffffba]" + ((Version.build == -1) ? "[#fc8140aa]custom build" : Version.modifier + " build " + Version.build);
parent.fill((x, y, w, h) -> {
float logoscl = (int)Unit.dp.scl(1);
float logow = Math.min(logo.getWidth() * logoscl, Core.graphics.getWidth() - Unit.dp.scl(20));
float logoh = logow * (float)logo.getHeight() / logo.getWidth();
float fx = (int)(Core.graphics.getWidth() / 2f);
float fy = (int)(Core.graphics.getHeight() - 6 - logoh) + logoh / 2 - (Core.graphics.isPortrait() ? Unit.dp.scl(30f) : 0f);
Draw.color();
Draw.rect(Draw.wrap(logo), fx, fy, logow, logoh);
Core.scene.skin.font().setColor(Color.WHITE);
Core.scene.skin.font().draw(versionText, fx, fy - logoh/2f, Align.center);
}).touchable(Touchable.disabled);
}
private void buildMobile(){
@@ -57,16 +82,17 @@ public class MenuFragment extends Fragment{
container.defaults().size(size).pad(5).padTop(4f);
MobileButton
play = new MobileButton("icon-play-2", isize, "$play", ui.deploy::show),
maps = new MobileButton("icon-map", isize, "$maps", ui.maps::show),
custom = new MobileButton("icon-play-custom", isize, "$customgame", this::showCustomSelect),
play = new MobileButton("icon-play-2", isize, "$campaign", ui.deploy::show),
custom = new MobileButton("icon-play-custom", isize, "$customgame", ui.custom::show),
maps = new MobileButton("icon-load", isize, "$loadgame", ui.load::show),
join = new MobileButton("icon-add", isize, "$joingame", ui.join::show),
editor = new MobileButton("icon-editor", isize, "$editor", () -> ui.loadAnd(ui.editor::show)),
editor = new MobileButton("icon-editor", isize, "$editor", ui.maps::show),
tools = new MobileButton("icon-tools", isize, "$settings", ui.settings::show),
donate = new MobileButton("icon-donate", isize, "$donate", () -> Core.net.openURI(donationURL)),
exit = new MobileButton("icon-exit", isize, "$quit", () -> Core.app.exit());
if(!Core.graphics.isPortrait()){
container.marginTop(60f);
container.add(play);
container.add(join);
container.add(custom);
@@ -83,6 +109,7 @@ public class MenuFragment extends Fragment{
table.add(exit);
}).colspan(4);
}else{
container.marginTop(0f);
container.add(play);
container.add(maps);
container.row();
@@ -103,54 +130,105 @@ public class MenuFragment extends Fragment{
}
private void buildDesktop(){
container.table(out -> {
container.clear();
container.setSize(Core.graphics.getWidth(), Core.graphics.getHeight());
float w = 200f;
float bw = w * 2f + 10f;
out.margin(16);
out.defaults().size(w, 66f).padTop(5).padRight(5);
float width = 230f;
String background = "flat";
out.add(new MenuButton("icon-play-2", "$play", ui.deploy::show)).width(bw).colspan(2);
container.left();
container.add().width(Core.graphics.getWidth()/10f);
container.table(background, t -> {
t.defaults().width(width).height(70f);
out.row();
buttons(t,
new Buttoni("$play", "icon-play-2",
new Buttoni("$campaign", "icon-play-2", ui.deploy::show),
new Buttoni("$joingame", "icon-add", ui.join::show),
new Buttoni("$customgame", "icon-terrain", ui.custom::show),
new Buttoni("$loadgame", "icon-load", ui.load::show)
),
new Buttoni("$editor", "icon-editor", ui.maps::show),
new Buttoni("$settings", "icon-tools", ui.settings::show),
new Buttoni("$about.button", "icon-info", ui.about::show),
new Buttoni("$quit", "icon-exit", Core.app::exit)
);
out.add(new MenuButton("icon-add", "$joingame", ui.join::show));
}).width(width).growY();
out.add(new MenuButton("icon-play-custom", "$customgame", this::showCustomSelect));
container.table(background, t -> {
submenu = t;
t.getColor().a = 0f;
t.top();
t.defaults().width(width).height(70f);
t.visible(() -> !t.getChildren().isEmpty());
out.row();
out.add(new MenuButton("icon-editor", "$editor", () -> ui.loadAnd(ui.editor::show)));
out.add(new MenuButton("icon-map", "$maps", ui.maps::show));
out.row();
out.add(new MenuButton("icon-info", "$about.button", ui.about::show));
out.add(new MenuButton("icon-tools", "$settings", ui.settings::show));
out.row();
out.add(new MenuButton("icon-exit", "$quit", Core.app::exit)).width(bw).colspan(2);
});
}).width(width).growY();
}
private void showCustomSelect(){
FloatingDialog dialog = new FloatingDialog("$play");
dialog.setFillParent(false);
dialog.addCloseButton();
dialog.cont.defaults().size(210f, 64f);
dialog.cont.add(new MenuButton("icon-editor", "$newgame", () -> {
dialog.hide();
ui.custom.show();
}));
dialog.cont.row();
dialog.cont.add(new MenuButton("icon-load", "$loadgame", () -> {
ui.load.show();
dialog.hide();
}));
dialog.show();
private void fadeInMenu(){
submenu.clearActions();
submenu.actions(Actions.alpha(1f, 0.15f, Interpolation.fade));
}
private void fadeOutMenu(){
//nothing to fade out
if(submenu.getChildren().isEmpty()){
return;
}
submenu.clearActions();
submenu.actions(Actions.alpha(1f), Actions.alpha(0f, 0.2f, Interpolation.fade), Actions.run(() -> submenu.clearChildren()));
}
private void buttons(Table t, Buttoni... buttons){
for(Buttoni b : buttons){
Button[] out = {null};
out[0] = t.addImageTextButton(b.text, b.icon + "-small", "clear-toggle-menu",
iconsizesmall, () -> {
if(currentMenu == out[0]){
currentMenu = null;
fadeOutMenu();
}else{
if(b.submenu != null){
currentMenu = out[0];
submenu.clearChildren();
fadeInMenu();
//correctly offset the button
submenu.add().height(Core.graphics.getHeight() - out[0].getY(Align.topLeft));
submenu.row();
buttons(submenu, b.submenu);
}else{
currentMenu = null;
fadeOutMenu();
b.runnable.run();
}
}
}).marginLeft(11f).get();
out[0].update(() -> out[0].setChecked(currentMenu == out[0]));
t.row();
}
}
private class Buttoni{
final String icon;
final String text;
final Runnable runnable;
final Buttoni[] submenu;
public Buttoni(String text, String icon, Runnable runnable){
this.icon = icon;
this.text = text;
this.runnable = runnable;
this.submenu = null;
}
public Buttoni(String text, String icon, Buttoni... buttons){
this.icon = icon;
this.text = text;
this.runnable = () -> {};
this.submenu = buttons;
}
}
}

View File

@@ -3,16 +3,15 @@ package io.anuke.mindustry.ui.fragments;
import io.anuke.arc.scene.Group;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.ui.layout.WidgetGroup;
import io.anuke.mindustry.input.InputHandler;
/** Fragment for displaying overlays such as block inventories. */
public class OverlayFragment extends Fragment{
public final BlockInventoryFragment inv;
public final BlockConfigFragment config;
private Group group = new WidgetGroup();
private WidgetGroup group = new WidgetGroup();
public OverlayFragment(InputHandler input){
public OverlayFragment(){
group.touchable(Touchable.childrenOnly);
inv = new BlockInventoryFragment();
config = new BlockConfigFragment();

View File

@@ -11,7 +11,6 @@ import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.style.TextureRegionDrawable;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.game.EventType.UnlockEvent;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
@@ -117,7 +116,7 @@ public class PlacementFragment extends Fragment{
public void build(Group parent){
parent.fill(full -> {
toggler = full;
full.bottom().right().visible(() -> !state.is(State.menu) && ui.hudfrag.shown());
full.bottom().right().visible(() -> ui.hudfrag.shown());
full.table(frame -> {
InputHandler input = control.input();
@@ -246,7 +245,7 @@ public class PlacementFragment extends Fragment{
});
}).colspan(3).fillX().visible(() -> getSelected() != null || tileDisplayBlock() != null).touchable(Touchable.enabled);
frame.row();
frame.addImage("blank").color(Pal.accent).colspan(3).height(3).growX();
frame.addImage("whiteui").color(Pal.gray).colspan(3).height(4).growX();
frame.row();
frame.table("pane-2", blocksSelect -> {
blocksSelect.margin(4).marginTop(0);
@@ -270,11 +269,11 @@ public class PlacementFragment extends Fragment{
if(f++ % 2 == 0) categories.row();
if(categoryEmpty[cat.ordinal()]){
categories.addImage("flat");
categories.addImage("flat-trans");
continue;
}
categories.addImageButton("icon-" + cat.name() + "-med", "clear-toggle", iconsizemed, () -> {
categories.addImageButton("icon-" + cat.name() + "-med", "clear-toggle-trans", iconsizemed, () -> {
currentCategory = cat;
rebuildCategory.run();
}).group(group).update(i -> i.setChecked(currentCategory == cat));

View File

@@ -135,7 +135,7 @@ public class PlayerListFragment extends Fragment{
content.add(button).padBottom(-6).width(350f).maxHeight(h + 14);
content.row();
content.addImage("blank").height(3f).color(state.rules.pvp ? user.getTeam().color : Pal.accent).growX();
content.addImage("whiteui").height(3f).color(state.rules.pvp ? user.getTeam().color : Pal.accent).growX();
content.row();
});

View File

@@ -301,7 +301,7 @@ public class Block extends BlockStorage{
@Override
public TextureRegion getContentIcon(){
return icon(Icon.large);
return icon(Icon.medium);
}
@Override

View File

@@ -0,0 +1,44 @@
package io.anuke.mindustry.world;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion;
import io.anuke.arc.util.Tmp;
import io.anuke.mindustry.world.blocks.StaticWall;
import static io.anuke.mindustry.Vars.tilesize;
public class StaticTree extends StaticWall{
public StaticTree(String name){
super(name);
}
@Override
public void draw(Tile tile){
TextureRegion r = Tmp.tr1;
r.set(region);
int crop = (region.getWidth() - tilesize*4) / 2;
float ox = 0;
float oy = 0;
for(int i = 0; i < 4; i++){
if(tile.getNearby(i) != null && tile.getNearby(i).block() instanceof StaticWall){
if(i == 0){
r.setWidth(r.getWidth() - crop);
ox -= crop /2f;
}else if(i == 1){
r.setY(r.getY() + crop);
oy -= crop /2f;
}else if(i == 2){
r.setX(r.getX() + crop);
ox += crop /2f;
}else{
r.setHeight(r.getHeight() - crop);
oy += crop /2f;
}
}
}
Draw.rect(r, tile.drawx() + ox * Draw.scl, tile.drawy() + oy * Draw.scl);
}
}

View File

@@ -1,15 +1,12 @@
package io.anuke.mindustry.world.blocks;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Mathf;
import io.anuke.mindustry.graphics.CacheLayer;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.*;
import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.world;
import static io.anuke.mindustry.Vars.*;
public class StaticWall extends Rock{
TextureRegion large;

View File

@@ -11,6 +11,7 @@ import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.consumers.*;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import static io.anuke.mindustry.Vars.tilesize;
@@ -30,6 +31,9 @@ public class LaserTurret extends PowerTurret{
super.setStats();
stats.remove(BlockStat.boostEffect);
stats.remove(BlockStat.damage);
//damages every 5 ticks, at least in meltdown's case
stats.add(BlockStat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond);
}
@Override

View File

@@ -2,6 +2,8 @@ package io.anuke.mindustry.world.blocks.defense.turrets;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
public abstract class PowerTurret extends CooledTurret{
protected BulletType shootType;
@@ -12,6 +14,13 @@ public abstract class PowerTurret extends CooledTurret{
hasPower = true;
}
@Override
public void setStats(){
super.setStats();
stats.add(BlockStat.damage, shootType.damage, StatUnit.none);
}
@Override
public void init(){
consumes.powerCond(powerUse, entity -> ((TurretEntity)entity).target != null);

View File

@@ -39,6 +39,7 @@ public enum BlockStat{
powerShot(StatCategory.shooting),
targetsAir(StatCategory.shooting),
targetsGround(StatCategory.shooting),
damage(StatCategory.shooting),
ammo(StatCategory.shooting),
booster(StatCategory.optional),