Merge branch 'master' into GH-v80
This commit is contained in:
83
core/src/io/anuke/mindustry/ui/Bar.java
Normal file
83
core/src/io/anuke/mindustry/ui/Bar.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.function.FloatProvider;
|
||||
import io.anuke.arc.function.Supplier;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.style.Drawable;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
|
||||
public class Bar extends Element{
|
||||
private static Rectangle scissor = new Rectangle();
|
||||
|
||||
private FloatProvider fraction;
|
||||
private String name = "";
|
||||
private float value, lastValue, blink;
|
||||
private Color blinkColor = new Color();
|
||||
|
||||
public Bar(String name, Color color, FloatProvider fraction){
|
||||
this.fraction = fraction;
|
||||
this.name = Core.bundle.get(name);
|
||||
this.blinkColor.set(color);
|
||||
lastValue = value = fraction.get();
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
public Bar(Supplier<String> name, Supplier<Color> color, FloatProvider fraction){
|
||||
this.fraction = fraction;
|
||||
lastValue = value = Mathf.clamp(fraction.get());
|
||||
update(() -> {
|
||||
this.name = name.get();
|
||||
this.blinkColor.set(color.get());
|
||||
setColor(color.get());
|
||||
});
|
||||
}
|
||||
|
||||
public Bar blink(Color color){
|
||||
blinkColor.set(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float computed = Mathf.clamp(fraction.get());
|
||||
if(!Mathf.isEqual(lastValue, computed)){
|
||||
blink = 1f;
|
||||
lastValue = computed;
|
||||
}
|
||||
|
||||
blink = Mathf.lerpDelta(blink, 0f, 0.2f);
|
||||
value = Mathf.lerpDelta(value, computed, 0.15f);
|
||||
|
||||
Draw.colorl(0.1f);
|
||||
Draw.drawable("bar", x, y, width, height);
|
||||
Draw.color(color, blinkColor, blink);
|
||||
|
||||
Drawable top = Core.scene.skin.getDrawable("bar-top");
|
||||
float topWidth = width * value;
|
||||
|
||||
if(topWidth > Core.atlas.find("bar-top").getWidth()){
|
||||
top.draw(x, y, topWidth, height);
|
||||
}else{
|
||||
if(ScissorStack.pushScissors(scissor.set(x, y, topWidth, height))){
|
||||
top.draw(x, y, Core.atlas.find("bar-top").getWidth(), height);
|
||||
ScissorStack.popScissors();
|
||||
}
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
BitmapFont font = Core.scene.skin.getFont("default-font");
|
||||
GlyphLayout lay = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
lay.setText(font, name);
|
||||
|
||||
font.setColor(Color.WHITE);
|
||||
font.draw(name, x + width / 2f - lay.width / 2f, y + height / 2f + lay.height / 2f + 1);
|
||||
|
||||
Pools.free(lay);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,43 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.graphics.Texture;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
public class BorderImage extends Image{
|
||||
private float thickness = 3f;
|
||||
|
||||
public BorderImage(){}
|
||||
|
||||
public BorderImage(Texture texture){
|
||||
super(texture);
|
||||
}
|
||||
|
||||
public BorderImage(Texture texture, float thick){
|
||||
super(texture);
|
||||
thickness = thick;
|
||||
}
|
||||
private float thickness = 3f;
|
||||
|
||||
public BorderImage(TextureRegion region, float thick){
|
||||
super(region);
|
||||
thickness = thick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float alpha){
|
||||
super.draw(batch, alpha);
|
||||
|
||||
float scaleX = getScaleX();
|
||||
float scaleY = getScaleY();
|
||||
|
||||
Draw.color(Colors.get("accent"));
|
||||
Lines.stroke(Unit.dp.scl(thickness));
|
||||
Lines.rect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY);
|
||||
Draw.reset();
|
||||
}
|
||||
public BorderImage(){
|
||||
|
||||
}
|
||||
|
||||
public BorderImage(Texture texture){
|
||||
super(texture);
|
||||
}
|
||||
|
||||
public BorderImage(Texture texture, float thick){
|
||||
super(texture);
|
||||
thickness = thick;
|
||||
}
|
||||
|
||||
public BorderImage(TextureRegion region, float thick){
|
||||
super(region);
|
||||
thickness = thick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
super.draw();
|
||||
|
||||
float scaleX = getScaleX();
|
||||
float scaleY = getScaleY();
|
||||
|
||||
Draw.color(Pal.accent);
|
||||
Draw.alpha(parentAlpha);
|
||||
Lines.stroke(Unit.dp.scl(thickness));
|
||||
Lines.rect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY);
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
|
||||
209
core/src/io/anuke/mindustry/ui/ContentDisplay.java
Normal file
209
core/src/io/anuke/mindustry/ui/ContentDisplay.java
Normal file
@@ -0,0 +1,209 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.OrderedMap;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
public class ContentDisplay{
|
||||
|
||||
public static void displayBlock(Table table, Block block){
|
||||
|
||||
table.table(title -> {
|
||||
int size = 8 * 6;
|
||||
|
||||
title.addImage(block.icon(Icon.large)).size(size);
|
||||
title.add("[accent]" + block.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(8).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(block.description != null){
|
||||
table.add(block.description).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(8).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
BlockStats stats = block.stats;
|
||||
|
||||
for(StatCategory cat : stats.toMap().keys()){
|
||||
OrderedMap<BlockStat, Array<StatValue>> map = stats.toMap().get(cat);
|
||||
|
||||
if(map.size == 0) continue;
|
||||
|
||||
table.add("$category." + cat.name()).color(Pal.accent).fillX();
|
||||
table.row();
|
||||
|
||||
for(BlockStat stat : map.keys()){
|
||||
table.table(inset -> {
|
||||
inset.left();
|
||||
inset.add("[LIGHT_GRAY]" + stat.localized() + ":[] ");
|
||||
Array<StatValue> arr = map.get(stat);
|
||||
for(StatValue value : arr){
|
||||
value.display(inset);
|
||||
inset.add().size(10f);
|
||||
}
|
||||
|
||||
//map.get(stat).display(inset);
|
||||
}).fillX().padLeft(10);
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void displayItem(Table table, Item item){
|
||||
|
||||
table.table(title -> {
|
||||
title.addImage(item.getContentIcon()).size(8 * 6);
|
||||
title.add("[accent]" + item.localizedName()).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(item.description != null){
|
||||
table.add(item.description).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
table.add(Core.bundle.format("item.explosiveness", (int)(item.explosiveness * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.flammability", (int)(item.flammability * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.radioactivity", (int)(item.radioactivity * 100)));
|
||||
table.row();
|
||||
}
|
||||
|
||||
public static void displayLiquid(Table table, Liquid liquid){
|
||||
|
||||
table.table(title -> {
|
||||
title.addImage(liquid.getContentIcon()).size(8 * 6);
|
||||
title.add("[accent]" + liquid.localizedName()).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(liquid.description != null){
|
||||
table.add(liquid.description).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
table.add(Core.bundle.format("item.explosiveness", (int)(liquid.explosiveness * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.flammability", (int)(liquid.flammability * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("liquid.heatcapacity", (int)(liquid.heatCapacity * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("liquid.temperature", (int)(liquid.temperature * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("liquid.viscosity", (int)(liquid.viscosity * 100)));
|
||||
table.row();
|
||||
}
|
||||
|
||||
public static void displayMech(Table table, Mech mech){
|
||||
table.table(title -> {
|
||||
title.addImage(mech.getContentIcon()).size(8 * 6);
|
||||
title.add("[accent]" + mech.localizedName()).padLeft(5);
|
||||
});
|
||||
table.left().defaults().left();
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(mech.description != null){
|
||||
table.add(mech.description).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
if(Core.bundle.has("mech." + mech.name + ".weapon")){
|
||||
table.add(Core.bundle.format("mech.weapon", Core.bundle.get("mech." + mech.name + ".weapon")));
|
||||
table.row();
|
||||
}
|
||||
if(Core.bundle.has("mech." + mech.name + ".ability")){
|
||||
table.add(Core.bundle.format("mech.ability", Core.bundle.get("mech." + mech.name + ".ability")));
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.add(Core.bundle.format("mech.buildspeed", (int)(mech.buildPower * 100f)));
|
||||
table.row();
|
||||
|
||||
table.add(Core.bundle.format("mech.health", (int)mech.health));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("mech.itemcapacity", mech.itemCapacity));
|
||||
table.row();
|
||||
|
||||
if(mech.drillPower > 0){
|
||||
table.add(Core.bundle.format("mech.minespeed", (int)(mech.mineSpeed * 100f)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("mech.minepower", mech.drillPower));
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
public static void displayUnit(Table table, UnitType unit){
|
||||
table.table(title -> {
|
||||
title.addImage(unit.getContentIcon()).size(8 * 6);
|
||||
title.add("[accent]" + unit.localizedName()).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(unit.description != null){
|
||||
table.add(unit.description).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
table.add(Core.bundle.format("unit.health", unit.health));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("unit.speed", Strings.fixed(unit.speed, 1)));
|
||||
table.row();
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,38 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
import io.anuke.arc.scene.Element;
|
||||
|
||||
public class GridImage extends Element{
|
||||
private int imageWidth, imageHeight;
|
||||
|
||||
public GridImage(int w, int h){
|
||||
this.imageWidth = w;
|
||||
this.imageHeight = h;
|
||||
}
|
||||
private int imageWidth, imageHeight;
|
||||
|
||||
public void draw(Batch batch, float alpha){
|
||||
TextureRegion blank = Draw.region("white");
|
||||
|
||||
float xspace = (getWidth() / imageWidth);
|
||||
float yspace = (getHeight() / imageHeight);
|
||||
float s = 1f;
|
||||
|
||||
for(int x = 0; x <= imageWidth; x ++){
|
||||
batch.draw(blank, (int)(getX() + xspace * x - s), getY() - s, 2, getHeight()+ (x == imageWidth ? 1: 0));
|
||||
}
|
||||
|
||||
for(int y = 0; y <= imageHeight; y ++){
|
||||
batch.draw(blank, getX() - s, (int)(getY() + y * yspace - s), getWidth(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageSize(int w, int h){
|
||||
this.imageWidth = w;
|
||||
this.imageHeight = h;
|
||||
}
|
||||
public GridImage(int w, int h){
|
||||
this.imageWidth = w;
|
||||
this.imageHeight = h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float xspace = (getWidth() / imageWidth);
|
||||
float yspace = (getHeight() / imageHeight);
|
||||
float s = 1f;
|
||||
|
||||
int minspace = 10;
|
||||
|
||||
int jumpx = (int)(Math.max(minspace, xspace) / xspace);
|
||||
int jumpy = (int)(Math.max(minspace, yspace) / yspace);
|
||||
|
||||
for(int x = 0; x <= imageWidth; x += jumpx){
|
||||
Fill.crect((int)(getX() + xspace * x - s), getY() - s, 2, getHeight() + (x == imageWidth ? 1 : 0));
|
||||
}
|
||||
|
||||
for(int y = 0; y <= imageHeight; y += jumpy){
|
||||
Fill.crect(getX() - s, (int)(getY() + y * yspace - s), getWidth(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageSize(int w, int h){
|
||||
this.imageWidth = w;
|
||||
this.imageHeight = h;
|
||||
}
|
||||
}
|
||||
|
||||
33
core/src/io/anuke/mindustry/ui/IntFormat.java
Normal file
33
core/src/io/anuke/mindustry/ui/IntFormat.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.function.Function;
|
||||
|
||||
/**
|
||||
* A low-garbage way to format bundle strings.
|
||||
*/
|
||||
public class IntFormat{
|
||||
private final StringBuilder builder = new StringBuilder();
|
||||
private final String text;
|
||||
private int lastValue = Integer.MIN_VALUE;
|
||||
private Function<Integer, String> converter = String::valueOf;
|
||||
|
||||
public IntFormat(String text){
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public IntFormat(String text, Function<Integer, String> converter){
|
||||
this.text = text;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public CharSequence get(int value){
|
||||
if(lastValue != value){
|
||||
builder.setLength(0);
|
||||
builder.append(Core.bundle.format(text, converter.get(value)));
|
||||
}
|
||||
lastValue = value;
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
23
core/src/io/anuke/mindustry/ui/ItemDisplay.java
Normal file
23
core/src/io/anuke/mindustry/ui/ItemDisplay.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
|
||||
/** An item image with text. */
|
||||
public class ItemDisplay extends Table{
|
||||
public final Item item;
|
||||
public final int amount;
|
||||
|
||||
public ItemDisplay(Item item){
|
||||
this(item, 0);
|
||||
}
|
||||
|
||||
public ItemDisplay(Item item, int amount){
|
||||
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4);
|
||||
add(item.localizedName()).padLeft(4);
|
||||
|
||||
this.item = item;
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
29
core/src/io/anuke/mindustry/ui/ItemImage.java
Normal file
29
core/src/io/anuke/mindustry/ui/ItemImage.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.type.Item.Icon;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
|
||||
public class ItemImage extends Stack{
|
||||
|
||||
public ItemImage(TextureRegion region, int amount){
|
||||
Table t = new Table().left().bottom();
|
||||
t.add(amount + "").name("item-label");
|
||||
|
||||
add(new Image(region));
|
||||
add(t);
|
||||
}
|
||||
|
||||
public ItemImage(ItemStack stack){
|
||||
add(new Image(stack.item.icon(Icon.large)));
|
||||
|
||||
if(stack.amount != 0){
|
||||
Table t = new Table().left().bottom();
|
||||
t.add(stack.amount + "").name("item-label");
|
||||
add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
core/src/io/anuke/mindustry/ui/ItemsDisplay.java
Normal file
44
core/src/io/anuke/mindustry/ui/ItemsDisplay.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.collection.ObjectIntMap;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Item.Icon;
|
||||
import io.anuke.mindustry.type.ItemType;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.data;
|
||||
|
||||
/** Displays a list of items, e.g. launched items.*/
|
||||
public class ItemsDisplay extends Table{
|
||||
private static final NumberFormat format = NumberFormat.getNumberInstance(Locale.getDefault());
|
||||
|
||||
public ItemsDisplay(){
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public void rebuild(){
|
||||
clear();
|
||||
top().left();
|
||||
margin(0);
|
||||
|
||||
table("flat", t -> {
|
||||
t.margin(10).marginLeft(15).marginTop(15f);
|
||||
t.add("$launcheditems").colspan(3).left().padBottom(5);
|
||||
t.row();
|
||||
ObjectIntMap<Item> items = data.items();
|
||||
for(Item item : content.items()){
|
||||
if(item.type == ItemType.material && data.isUnlocked(item)){
|
||||
t.label(() -> format.format(items.get(item, 0))).left();
|
||||
t.addImage(item.icon(Icon.medium)).size(8 * 3).padLeft(4).padRight(4);
|
||||
t.add(item.localizedName()).color(Color.LIGHT_GRAY).left();
|
||||
t.row();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,28 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
|
||||
public class Links {
|
||||
private static final LinkEntry[] links = {
|
||||
new LinkEntry("discord", "https://discord.gg/BKADYds", Color.valueOf("7289da")),
|
||||
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", "http://mindustry.wikia.com/wiki/Mindustry_Wiki", Color.valueOf("0f142f")),
|
||||
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://github.com/Anuken/Mindustry/wiki", Color.valueOf("fafbfc")),
|
||||
};
|
||||
new LinkEntry("dev-builds", "https://jenkins.hellomouse.net/job/mindustry/", Color.valueOf("fafbfc"))
|
||||
};
|
||||
}
|
||||
|
||||
public static LinkEntry[] getLinks(){
|
||||
if(links == null){
|
||||
createLinks();
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
@@ -22,10 +30,10 @@ public class Links {
|
||||
public final String name, description, link;
|
||||
public final Color color;
|
||||
|
||||
public LinkEntry(String name, String link, Color color) {
|
||||
public LinkEntry(String name, String link, Color color){
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
this.description = Bundles.getNotNull("text.link." + name +".description");
|
||||
this.description = Core.bundle.getNotNull("link." + name + ".description");
|
||||
this.link = link;
|
||||
}
|
||||
}
|
||||
|
||||
38
core/src/io/anuke/mindustry/ui/LiquidDisplay.java
Normal file
38
core/src/io/anuke/mindustry/ui/LiquidDisplay.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.meta.StatUnit;
|
||||
|
||||
/** An ItemDisplay, but for liquids. */
|
||||
public class LiquidDisplay extends Table{
|
||||
public final Liquid liquid;
|
||||
public final float amount;
|
||||
public final boolean perSecond;
|
||||
|
||||
public LiquidDisplay(Liquid liquid, float amount, boolean perSecond){
|
||||
this.liquid = liquid;
|
||||
this.amount = amount;
|
||||
this.perSecond = perSecond;
|
||||
|
||||
add(new Stack(){{
|
||||
add(new Image(liquid.getContentIcon()));
|
||||
|
||||
if(amount != 0){
|
||||
Table t = new Table().left().bottom();
|
||||
t.add(Strings.autoFixed(amount, 1));
|
||||
add(t);
|
||||
}
|
||||
}}).size(8 * 4).padRight(3);
|
||||
|
||||
if(perSecond){
|
||||
add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.LIGHT_GRAY);
|
||||
}
|
||||
|
||||
add(liquid.localizedName());
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,33 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.ucore.function.Listenable;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.util.Align;
|
||||
|
||||
import static io.anuke.mindustry.Vars.iconsize;
|
||||
|
||||
public class MenuButton extends TextButton{
|
||||
|
||||
public MenuButton(String icon, String text, Listenable clicked){
|
||||
this(icon, text, null, clicked);
|
||||
}
|
||||
|
||||
public MenuButton(String icon, String text, String description, Listenable clicked){
|
||||
super("default");
|
||||
float s = 70f;
|
||||
public MenuButton(String icon, String text, Runnable clicked){
|
||||
this(icon, text, null, clicked);
|
||||
}
|
||||
|
||||
clicked(clicked);
|
||||
public MenuButton(String icon, String text, String description, Runnable clicked){
|
||||
super("default");
|
||||
|
||||
clearChildren();
|
||||
clicked(clicked);
|
||||
clearChildren();
|
||||
|
||||
margin(0);
|
||||
margin(0);
|
||||
|
||||
table(t -> {
|
||||
t.addImage(icon).size(14*3);
|
||||
t.update(() -> t.setBackground(getClickListener().isOver() || getClickListener().isVisualPressed() ? "button-over" : "button"));
|
||||
}).size(s - 5, s);
|
||||
table(t -> {
|
||||
t.addImage(icon).size(iconsize).padLeft(6);
|
||||
|
||||
|
||||
table(t -> {
|
||||
t.add(text).wrap().growX().get().setAlignment(Align.center, Align.left);
|
||||
if(description != null){
|
||||
t.row();
|
||||
t.add(description).color(Color.LIGHT_GRAY);
|
||||
}
|
||||
}).padLeft(5).growX();
|
||||
}
|
||||
t.add(text).wrap().growX().get().setAlignment(Align.center, Align.left);
|
||||
if(description != null){
|
||||
t.row();
|
||||
t.add(description).color(Color.LIGHT_GRAY);
|
||||
}
|
||||
}).padLeft(5).growX();
|
||||
}
|
||||
}
|
||||
|
||||
99
core/src/io/anuke/mindustry/ui/Minimap.java
Normal file
99
core/src/io/anuke/mindustry/ui/Minimap.java
Normal file
@@ -0,0 +1,99 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.event.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Minimap extends Table{
|
||||
|
||||
public Minimap(){
|
||||
background("pane");
|
||||
float margin = 5f;
|
||||
touchable(Touchable.enabled);
|
||||
|
||||
add(new Element(){
|
||||
{
|
||||
setSize(Unit.dp.scl(140f));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta){
|
||||
setPosition(margin, margin);
|
||||
|
||||
super.act(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
if(renderer.minimap.getRegion() == null) return;
|
||||
|
||||
Draw.rect(renderer.minimap.getRegion(), x + width / 2f, y + height / 2f, width, height);
|
||||
|
||||
if(renderer.minimap.getTexture() != null){
|
||||
renderer.minimap.drawEntities(x, y, width, height);
|
||||
}
|
||||
}
|
||||
}).size(140f);
|
||||
|
||||
margin(margin);
|
||||
|
||||
addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean scrolled(InputEvent event, float x, float y, float amountx, float amounty){
|
||||
renderer.minimap.zoomBy(amounty);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
addListener(new ClickListener(){
|
||||
{
|
||||
tapSquareSize = Unit.dp.scl(11f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
if(inTapSquare()){
|
||||
super.touchUp(event, x, y, pointer, button);
|
||||
}else{
|
||||
pressed = false;
|
||||
pressedPointer = -1;
|
||||
pressedButton = null;
|
||||
cancelled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchDragged(InputEvent event, float x, float y, int pointer){
|
||||
if(!inTapSquare(x, y)){
|
||||
invalidateTapSquare();
|
||||
}
|
||||
super.touchDragged(event, x, y, pointer);
|
||||
|
||||
if(mobile){
|
||||
float max = Math.min(world.width(), world.height()) / 16f / 2f;
|
||||
renderer.minimap.setZoom(1f + y / height * (max - 1f));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clicked(InputEvent event, float x, float y){
|
||||
ui.minimap.show();
|
||||
}
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
|
||||
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(e != null && e.isDescendantOf(this)){
|
||||
Core.scene.setScrollFocus(this);
|
||||
}else if(Core.scene.getScrollFocus() == this){
|
||||
Core.scene.setScrollFocus(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
15
core/src/io/anuke/mindustry/ui/MobileButton.java
Normal file
15
core/src/io/anuke/mindustry/ui/MobileButton.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.util.Align;
|
||||
|
||||
public class MobileButton extends ImageButton{
|
||||
|
||||
public MobileButton(String icon, float isize, String text, Runnable listener){
|
||||
super(icon);
|
||||
resizeImage(isize);
|
||||
clicked(listener);
|
||||
row();
|
||||
add(text).growX().wrap().center().get().setAlignment(Align.center, Align.center);
|
||||
}
|
||||
}
|
||||
31
core/src/io/anuke/mindustry/ui/MultiReqImage.java
Normal file
31
core/src/io/anuke/mindustry/ui/MultiReqImage.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.util.Time;
|
||||
|
||||
public class MultiReqImage extends Stack{
|
||||
private Array<ReqImage> displays = new Array<>();
|
||||
private float time;
|
||||
|
||||
public void add(ReqImage display){
|
||||
displays.add(display);
|
||||
super.add(display);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta){
|
||||
super.act(delta);
|
||||
|
||||
time += Time.delta() / 60f;
|
||||
|
||||
displays.each(req -> req.visible(false));
|
||||
|
||||
ReqImage valid = displays.find(ReqImage::valid);
|
||||
if(valid != null){
|
||||
valid.visible(true);
|
||||
}else{
|
||||
displays.get((int)(time) % displays.size).visible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import io.anuke.ucore.scene.ui.Button;
|
||||
|
||||
public class PressGroup{
|
||||
private Array<Button> buttons = new Array<>();
|
||||
private boolean active = true;
|
||||
|
||||
public void add(Button button){
|
||||
//TODO make only one button in the group be clickable, add implementation
|
||||
buttons.add(button);
|
||||
}
|
||||
|
||||
}
|
||||
40
core/src/io/anuke/mindustry/ui/ReqImage.java
Normal file
40
core/src/io/anuke/mindustry/ui/ReqImage.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.function.BooleanProvider;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
public class ReqImage extends Stack{
|
||||
private final BooleanProvider valid;
|
||||
|
||||
public ReqImage(Element image, BooleanProvider valid){
|
||||
this.valid = valid;
|
||||
add(image);
|
||||
add(new Element(){
|
||||
{
|
||||
visible(() -> !valid.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Lines.stroke(Unit.dp.scl(2f), Pal.removeBack);
|
||||
Lines.line(x, y - 2f + height, x + width, y - 2f);
|
||||
Draw.color(Pal.remove);
|
||||
Lines.line(x, y + height, x + width, y);
|
||||
Draw.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ReqImage(TextureRegion region, BooleanProvider valid){
|
||||
this(new Image(region), valid);
|
||||
}
|
||||
|
||||
public boolean valid(){
|
||||
return valid.get();
|
||||
}
|
||||
}
|
||||
307
core/src/io/anuke/mindustry/ui/TreeLayout.java
Normal file
307
core/src/io/anuke/mindustry/ui/TreeLayout.java
Normal file
@@ -0,0 +1,307 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.collection.FloatArray;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
|
||||
/**
|
||||
* Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>.
|
||||
*/
|
||||
public class TreeLayout{
|
||||
public TreeLocation rootLocation = TreeLocation.top;
|
||||
public TreeAlignment alignment = TreeAlignment.awayFromRoot;
|
||||
public float gapBetweenLevels = 10;
|
||||
public float gapBetweenNodes = 10f;
|
||||
|
||||
private final FloatArray sizeOfLevel = new FloatArray();
|
||||
private float boundsLeft = Float.MAX_VALUE;
|
||||
private float boundsRight = Float.MIN_VALUE;
|
||||
private float boundsTop = Float.MAX_VALUE;
|
||||
private float boundsBottom = Float.MIN_VALUE;
|
||||
|
||||
public void layout(TreeNode root){
|
||||
firstWalk(root, null);
|
||||
calcSizeOfLevels(root, 0);
|
||||
secondWalk(root, -root.prelim, 0, 0);
|
||||
}
|
||||
|
||||
private float getWidthOrHeightOfNode(TreeNode treeNode, boolean returnWidth){
|
||||
return returnWidth ? treeNode.width : treeNode.height;
|
||||
}
|
||||
|
||||
private float getNodeThickness(TreeNode treeNode){
|
||||
return getWidthOrHeightOfNode(treeNode, !isLevelChangeInYAxis());
|
||||
}
|
||||
|
||||
private float getNodeSize(TreeNode treeNode){
|
||||
return getWidthOrHeightOfNode(treeNode, isLevelChangeInYAxis());
|
||||
}
|
||||
|
||||
private boolean isLevelChangeInYAxis(){
|
||||
return rootLocation == TreeLocation.top || rootLocation == TreeLocation.bottom;
|
||||
}
|
||||
|
||||
private int getLevelChangeSign(){
|
||||
return rootLocation == TreeLocation.bottom || rootLocation == TreeLocation.right ? -1 : 1;
|
||||
}
|
||||
|
||||
private void updateBounds(TreeNode node, float centerX, float centerY){
|
||||
float width = node.width;
|
||||
float height = node.height;
|
||||
float left = centerX - width / 2;
|
||||
float right = centerX + width / 2;
|
||||
float top = centerY - height / 2;
|
||||
float bottom = centerY + height / 2;
|
||||
if(boundsLeft > left){
|
||||
boundsLeft = left;
|
||||
}
|
||||
if(boundsRight < right){
|
||||
boundsRight = right;
|
||||
}
|
||||
if(boundsTop > top){
|
||||
boundsTop = top;
|
||||
}
|
||||
if(boundsBottom < bottom){
|
||||
boundsBottom = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle getBounds(){
|
||||
return new Rectangle(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom);
|
||||
}
|
||||
|
||||
private void calcSizeOfLevels(TreeNode node, int level){
|
||||
float oldSize;
|
||||
if(sizeOfLevel.size <= level){
|
||||
sizeOfLevel.add(0);
|
||||
oldSize = 0;
|
||||
}else{
|
||||
oldSize = sizeOfLevel.get(level);
|
||||
}
|
||||
|
||||
float size = getNodeThickness(node);
|
||||
if(oldSize < size){
|
||||
sizeOfLevel.set(level, size);
|
||||
}
|
||||
|
||||
if(!node.isLeaf()){
|
||||
for(TreeNode child : node.children){
|
||||
calcSizeOfLevels(child, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getLevelCount(){
|
||||
return sizeOfLevel.size;
|
||||
}
|
||||
|
||||
public float getGapBetweenNodes(TreeNode a, TreeNode b){
|
||||
return gapBetweenNodes;
|
||||
}
|
||||
|
||||
public float getSizeOfLevel(int level){
|
||||
if(!(level >= 0)) throw new IllegalArgumentException("level must be >= 0");
|
||||
if(!(level < getLevelCount())) throw new IllegalArgumentException("level must be < levelCount");
|
||||
|
||||
return sizeOfLevel.get(level);
|
||||
}
|
||||
|
||||
private TreeNode getAncestor(TreeNode node){
|
||||
return node.ancestor != null ? node.ancestor : node;
|
||||
}
|
||||
|
||||
private float getDistance(TreeNode v, TreeNode w){
|
||||
float sizeOfNodes = getNodeSize(v) + getNodeSize(w);
|
||||
|
||||
return sizeOfNodes / 2 + getGapBetweenNodes(v, w);
|
||||
}
|
||||
|
||||
private TreeNode nextLeft(TreeNode v){
|
||||
return v.isLeaf() ? v.thread : v.children[0];
|
||||
}
|
||||
|
||||
private TreeNode nextRight(TreeNode v){
|
||||
return v.isLeaf() ? v.thread : v.children[v.children.length - 1];
|
||||
}
|
||||
|
||||
private int getNumber(TreeNode node, TreeNode parentNode){
|
||||
if(node.number == -1){
|
||||
int number = 1;
|
||||
for(TreeNode child : parentNode.children){
|
||||
child.number = number++;
|
||||
}
|
||||
}
|
||||
return node.number;
|
||||
}
|
||||
|
||||
private TreeNode ancestor(TreeNode vIMinus, TreeNode parentOfV, TreeNode defaultAncestor){
|
||||
TreeNode ancestor = getAncestor(vIMinus);
|
||||
return ancestor.parent == parentOfV ? ancestor : defaultAncestor;
|
||||
}
|
||||
|
||||
private void moveSubtree(TreeNode wMinus, TreeNode wPlus, TreeNode parent, float shift){
|
||||
int subtrees = getNumber(wPlus, parent) - getNumber(wMinus, parent);
|
||||
wPlus.change = wPlus.change - shift / subtrees;
|
||||
wPlus.shift = wPlus.shift + shift;
|
||||
wMinus.change = wMinus.change + shift / subtrees;
|
||||
wPlus.prelim = wPlus.prelim + shift;
|
||||
wPlus.mode = wPlus.mode + shift;
|
||||
}
|
||||
|
||||
private TreeNode apportion(TreeNode v, TreeNode defaultAncestor,
|
||||
TreeNode leftSibling, TreeNode parentOfV){
|
||||
if(leftSibling == null){
|
||||
return defaultAncestor;
|
||||
}
|
||||
|
||||
TreeNode vOPlus = v;
|
||||
TreeNode vIPlus = v;
|
||||
TreeNode vIMinus = leftSibling;
|
||||
|
||||
TreeNode vOMinus = parentOfV.children[0];
|
||||
|
||||
float sIPlus = (vIPlus).mode;
|
||||
float sOPlus = (vOPlus).mode;
|
||||
float sIMinus = (vIMinus).mode;
|
||||
float sOMinus = (vOMinus).mode;
|
||||
|
||||
TreeNode nextRightVIMinus = nextRight(vIMinus);
|
||||
TreeNode nextLeftVIPlus = nextLeft(vIPlus);
|
||||
|
||||
while(nextRightVIMinus != null && nextLeftVIPlus != null){
|
||||
vIMinus = nextRightVIMinus;
|
||||
vIPlus = nextLeftVIPlus;
|
||||
vOMinus = nextLeft(vOMinus);
|
||||
vOPlus = nextRight(vOPlus);
|
||||
vOPlus.ancestor = v;
|
||||
float shift = (vIMinus.prelim + sIMinus)
|
||||
- (vIPlus.prelim + sIPlus)
|
||||
+ getDistance(vIMinus, vIPlus);
|
||||
|
||||
if(shift > 0){
|
||||
moveSubtree(ancestor(vIMinus, parentOfV, defaultAncestor),
|
||||
v, parentOfV, shift);
|
||||
sIPlus = sIPlus + shift;
|
||||
sOPlus = sOPlus + shift;
|
||||
}
|
||||
sIMinus += vIMinus.mode;
|
||||
sIPlus += vIPlus.mode;
|
||||
sOMinus += vOMinus.mode;
|
||||
sOPlus += vOPlus.mode;
|
||||
|
||||
nextRightVIMinus = nextRight(vIMinus);
|
||||
nextLeftVIPlus = nextLeft(vIPlus);
|
||||
}
|
||||
|
||||
if(nextRightVIMinus != null && nextRight(vOPlus) == null){
|
||||
vOPlus.thread = nextRightVIMinus;
|
||||
vOPlus.mode += sIMinus - sOPlus;
|
||||
}
|
||||
|
||||
if(nextLeftVIPlus != null && nextLeft(vOMinus) == null){
|
||||
vOMinus.thread = nextLeftVIPlus;
|
||||
vOMinus.mode += sIPlus - sOMinus;
|
||||
defaultAncestor = v;
|
||||
}
|
||||
return defaultAncestor;
|
||||
}
|
||||
|
||||
private void executeShifts(TreeNode v){
|
||||
float shift = 0;
|
||||
float change = 0;
|
||||
|
||||
for(int i = v.children.length - 1; i >= 0; i--){
|
||||
TreeNode w = v.children[i];
|
||||
change = change + w.change;
|
||||
w.prelim += shift;
|
||||
w.mode += shift;
|
||||
shift += w.shift + change;
|
||||
}
|
||||
}
|
||||
|
||||
private void firstWalk(TreeNode v, TreeNode leftSibling){
|
||||
if(v.isLeaf()){
|
||||
if(leftSibling != null){
|
||||
v.prelim = leftSibling.prelim + getDistance(v, leftSibling);
|
||||
}
|
||||
|
||||
}else{
|
||||
TreeNode defaultAncestor = v.children[0];
|
||||
TreeNode previousChild = null;
|
||||
for(TreeNode w : v.children){
|
||||
firstWalk(w, previousChild);
|
||||
defaultAncestor = apportion(w, defaultAncestor, previousChild,
|
||||
v);
|
||||
previousChild = w;
|
||||
}
|
||||
executeShifts(v);
|
||||
float midpoint = (v.children[0].prelim + v.children[v.children.length - 1].prelim) / 2f;
|
||||
if(leftSibling != null){
|
||||
v.prelim = leftSibling.prelim + getDistance(v, leftSibling);
|
||||
v.mode = v.prelim - midpoint;
|
||||
}else{
|
||||
v.prelim = midpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void secondWalk(TreeNode v, float m, int level, float levelStart){
|
||||
float levelChangeSign = getLevelChangeSign();
|
||||
boolean levelChangeOnYAxis = isLevelChangeInYAxis();
|
||||
float levelSize = getSizeOfLevel(level);
|
||||
|
||||
float x = v.prelim + m;
|
||||
|
||||
float y;
|
||||
if(alignment == TreeAlignment.center){
|
||||
y = levelStart + levelChangeSign * (levelSize / 2);
|
||||
}else if(alignment == TreeAlignment.towardsRoot){
|
||||
y = levelStart + levelChangeSign * (getNodeThickness(v) / 2);
|
||||
}else{
|
||||
y = levelStart + levelSize - levelChangeSign
|
||||
* (getNodeThickness(v) / 2);
|
||||
}
|
||||
|
||||
if(!levelChangeOnYAxis){
|
||||
float t = x;
|
||||
x = y;
|
||||
y = t;
|
||||
}
|
||||
|
||||
v.x = x;
|
||||
v.y = y;
|
||||
updateBounds(v, x, y);
|
||||
|
||||
if(!v.isLeaf()){
|
||||
float nextLevelStart = levelStart
|
||||
+ (levelSize + gapBetweenLevels)
|
||||
* levelChangeSign;
|
||||
for(TreeNode w : v.children){
|
||||
secondWalk(w, m + v.mode, level + 1, nextLevelStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum TreeLocation{
|
||||
top, left, bottom, right
|
||||
}
|
||||
|
||||
public enum TreeAlignment{
|
||||
center, towardsRoot, awayFromRoot
|
||||
}
|
||||
|
||||
public static class TreeNode<T extends TreeNode>{
|
||||
public float width, height, x, y;
|
||||
|
||||
//should be initialized by user
|
||||
public T[] children;
|
||||
public T parent;
|
||||
|
||||
private float mode, prelim, change, shift;
|
||||
private int number = -1;
|
||||
private TreeNode thread, ancestor;
|
||||
|
||||
boolean isLeaf(){
|
||||
return children == null || children.length == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,49 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.ui.Links;
|
||||
import io.anuke.mindustry.ui.Links.LinkEntry;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ios;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class AboutDialog extends FloatingDialog {
|
||||
public class AboutDialog extends FloatingDialog{
|
||||
private Array<String> contributors = new Array<>();
|
||||
private static ObjectSet<String> bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "trello");
|
||||
|
||||
public AboutDialog(){
|
||||
super("$text.about.button");
|
||||
super("$about.button");
|
||||
|
||||
addCloseButton();
|
||||
shown(() -> {
|
||||
contributors = Array.with(Core.files.internal("contributors").readString().split("\n"));
|
||||
Core.app.post(this::setup);
|
||||
});
|
||||
|
||||
float h = 80f;
|
||||
float w = 600f;
|
||||
shown(this::setup);
|
||||
onResize(this::setup);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
buttons.clear();
|
||||
|
||||
float h = Core.graphics.isPortrait() ? 90f : 80f;
|
||||
float w = Core.graphics.isPortrait() ? 330f : 600f;
|
||||
|
||||
Table in = new Table();
|
||||
ScrollPane pane = new ScrollPane(in, "clear");
|
||||
ScrollPane pane = new ScrollPane(in);
|
||||
|
||||
for(LinkEntry link : Links.getLinks()){
|
||||
if((ios || OS.isMac) && bannedItems.contains(link.name)){ //because Apple doesn't like me mentioning things
|
||||
continue;
|
||||
}
|
||||
|
||||
Table table = new Table("button");
|
||||
Table table = new Table("underline");
|
||||
table.margin(0);
|
||||
table.table(img -> {
|
||||
img.addImage("white").height(h - 5).width(40f).color(link.color);
|
||||
@@ -42,42 +52,67 @@ public class AboutDialog extends FloatingDialog {
|
||||
}).expandY();
|
||||
|
||||
table.table(i -> {
|
||||
i.background("button");
|
||||
i.addImage("icon-" + link.name).size(14*3f);
|
||||
}).size(h-5, h);
|
||||
i.background("button-edge-3");
|
||||
i.addImage("icon-" + link.name).size(iconsize);
|
||||
}).size(h - 5, h);
|
||||
|
||||
table.table(inset -> {
|
||||
inset.add("[accent]"+link.name.replace("-", " ")).growX().left();
|
||||
inset.add("[accent]" + Strings.capitalize(link.name.replace("-", " "))).growX().left();
|
||||
inset.row();
|
||||
inset.labelWrap(link.description).width(w - 100f).color(Color.LIGHT_GRAY).growX();
|
||||
}).padLeft(8);
|
||||
|
||||
table.addImageButton("icon-link", 14*3, () -> {
|
||||
if(!Gdx.net.openURI(link.link)){
|
||||
ui.showError("$text.linkfail");
|
||||
Gdx.app.getClipboard().setContents(link.link);
|
||||
table.addImageButton("icon-link", iconsize, () -> {
|
||||
if(!Core.net.openURI(link.link)){
|
||||
ui.showError("$linkfail");
|
||||
Core.app.getClipboard().setContents(link.link);
|
||||
}
|
||||
}).size(h-5, h);
|
||||
}).size(h - 5, h);
|
||||
|
||||
in.add(table).size(w, h).padTop(5).row();
|
||||
}
|
||||
|
||||
shown(() -> Timers.run(1f, () -> Core.scene.setScrollFocus(pane)));
|
||||
shown(() -> Time.run(1f, () -> Core.scene.setScrollFocus(pane)));
|
||||
|
||||
content().add(pane).growX();
|
||||
cont.add(pane).growX();
|
||||
|
||||
buttons().addButton("$text.credits", this::showCredits).size(200f, 64f);
|
||||
addCloseButton();
|
||||
|
||||
buttons.addButton("$credits", this::showCredits).size(200f, 64f);
|
||||
|
||||
if(!ios && !OS.isMac){
|
||||
buttons().addButton("$text.changelog.title", ui.changelog::show).size(200f, 64f);
|
||||
buttons.addButton("$changelog.title", ui.changelog::show).size(200f, 64f);
|
||||
}
|
||||
|
||||
if(Core.graphics.isPortrait()){
|
||||
for(Cell<?> cell : buttons.getCells()){
|
||||
cell.width(140f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void showCredits(){
|
||||
FloatingDialog dialog = new FloatingDialog("$text.credits");
|
||||
FloatingDialog dialog = new FloatingDialog("$credits");
|
||||
dialog.addCloseButton();
|
||||
dialog.content().add("$text.about");
|
||||
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.row();
|
||||
dialog.cont.add("$contributors");
|
||||
dialog.cont.row();
|
||||
dialog.cont.pane(new Table(){{
|
||||
int i = 0;
|
||||
left();
|
||||
for(String c : contributors){
|
||||
add("[lightgray]" + c).left().pad(3).padLeft(6).padRight(6);
|
||||
if(++i % 3 == 0){
|
||||
row();
|
||||
}
|
||||
}
|
||||
}});
|
||||
}
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class AdminsDialog extends FloatingDialog {
|
||||
public class AdminsDialog extends FloatingDialog{
|
||||
|
||||
public AdminsDialog(){
|
||||
super("$text.server.admins");
|
||||
super("$server.admins");
|
||||
|
||||
addCloseButton();
|
||||
|
||||
@@ -22,19 +18,17 @@ public class AdminsDialog extends FloatingDialog {
|
||||
}
|
||||
|
||||
private void setup(){
|
||||
content().clear();
|
||||
|
||||
if(gwt) return;
|
||||
cont.clear();
|
||||
|
||||
float w = 400f, h = 80f;
|
||||
|
||||
Table table = new Table();
|
||||
|
||||
ScrollPane pane = new ScrollPane(table, "clear");
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
if(netServer.admins.getAdmins().size == 0){
|
||||
table.add("$text.server.admins.none");
|
||||
table.add("$server.admins.none");
|
||||
}
|
||||
|
||||
for(PlayerInfo info : netServer.admins.getAdmins()){
|
||||
@@ -43,16 +37,14 @@ public class AdminsDialog extends FloatingDialog {
|
||||
|
||||
res.labelWrap("[LIGHT_GRAY]" + info.lastName).width(w - h - 24f);
|
||||
res.add().growX();
|
||||
res.addImageButton("icon-cancel", 14*3, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
|
||||
res.addImageButton("icon-cancel", iconsize, () -> {
|
||||
ui.showConfirm("$confirm", "$confirmunadmin", () -> {
|
||||
netServer.admins.unAdminPlayer(info.id);
|
||||
for(Player player : playerGroup.all()){
|
||||
NetConnection c = Net.getConnection(player.clientid);
|
||||
if(c != null){
|
||||
NetEvents.handleAdminSet(player, false);
|
||||
break;
|
||||
playerGroup.all().each(player -> {
|
||||
if(player != null && player.uuid != null && player.uuid.equals(info.id)){
|
||||
player.isAdmin = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
setup();
|
||||
});
|
||||
}).size(h).pad(-14f);
|
||||
@@ -61,6 +53,6 @@ public class AdminsDialog extends FloatingDialog {
|
||||
table.row();
|
||||
}
|
||||
|
||||
content().add(pane);
|
||||
cont.add(pane);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class BansDialog extends FloatingDialog {
|
||||
public class BansDialog extends FloatingDialog{
|
||||
|
||||
public BansDialog(){
|
||||
super("$text.server.bans");
|
||||
super("$server.bans");
|
||||
|
||||
addCloseButton();
|
||||
|
||||
@@ -19,19 +19,17 @@ public class BansDialog extends FloatingDialog {
|
||||
}
|
||||
|
||||
private void setup(){
|
||||
content().clear();
|
||||
|
||||
if(gwt) return;
|
||||
cont.clear();
|
||||
|
||||
float w = 400f, h = 80f;
|
||||
|
||||
Table table = new Table();
|
||||
|
||||
ScrollPane pane = new ScrollPane(table, "clear");
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
if(netServer.admins.getBanned().size == 0){
|
||||
table.add("$text.server.bans.none");
|
||||
table.add("$server.bans.none");
|
||||
}
|
||||
|
||||
for(PlayerInfo info : netServer.admins.getBanned()){
|
||||
@@ -40,8 +38,8 @@ public class BansDialog extends FloatingDialog {
|
||||
|
||||
res.labelWrap("IP: [LIGHT_GRAY]" + info.lastIP + "\n[]Name: [LIGHT_GRAY]" + info.lastName).width(w - h - 24f);
|
||||
res.add().growX();
|
||||
res.addImageButton("icon-cancel", 14*3, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.confirmunban", () -> {
|
||||
res.addImageButton("icon-cancel", iconsize, () -> {
|
||||
ui.showConfirm("$confirm", "$confirmunban", () -> {
|
||||
netServer.admins.unbanPlayerID(info.id);
|
||||
setup();
|
||||
});
|
||||
@@ -51,6 +49,6 @@ public class BansDialog extends FloatingDialog {
|
||||
table.row();
|
||||
}
|
||||
|
||||
content().add(pane);
|
||||
cont.add(pane);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
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 io.anuke.mindustry.io.Version;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ios;
|
||||
|
||||
@@ -19,40 +18,42 @@ public class ChangelogDialog extends FloatingDialog{
|
||||
private Array<VersionInfo> versions;
|
||||
|
||||
public ChangelogDialog(){
|
||||
super("$text.changelog.title");
|
||||
super("$changelog.title");
|
||||
|
||||
addCloseButton();
|
||||
|
||||
content().add("$text.changelog.loading");
|
||||
cont.add("$changelog.loading");
|
||||
|
||||
if(!ios && !OS.isMac) {
|
||||
Changelogs.getChangelog(result -> {
|
||||
versions = result;
|
||||
Gdx.app.postRunnable(this::setup);
|
||||
}, t -> {
|
||||
Log.err(t);
|
||||
Gdx.app.postRunnable(this::setup);
|
||||
});
|
||||
}
|
||||
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, "clear");
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
|
||||
content().clear();
|
||||
content().add(pane).grow();
|
||||
cont.clear();
|
||||
cont.add(pane).grow();
|
||||
|
||||
if(versions == null){
|
||||
table.add("$text.changelog.error");
|
||||
table.add("$changelog.error");
|
||||
if(Vars.android){
|
||||
table.row();
|
||||
table.add("$text.changelog.error.android").padTop(8);
|
||||
table.add("$changelog.error.android").padTop(8);
|
||||
}
|
||||
|
||||
if(ios){
|
||||
table.row();
|
||||
table.add("$text.changelog.error.ios").padTop(8);
|
||||
table.add("$changelog.error.ios").padTop(8);
|
||||
}
|
||||
}else{
|
||||
for(VersionInfo info : versions){
|
||||
@@ -60,16 +61,16 @@ public class ChangelogDialog extends FloatingDialog{
|
||||
|
||||
desc = desc.replace("Android", "Mobile");
|
||||
|
||||
Table in = new Table("clear");
|
||||
Table in = new Table("underline");
|
||||
in.top().left().margin(10);
|
||||
|
||||
in.add("[accent]" + info.name);
|
||||
in.add("[accent]" + info.name + "[LIGHT_GRAY] | " + info.date);
|
||||
if(info.build == Version.build){
|
||||
in.row();
|
||||
in.add("$text.changelog.current");
|
||||
in.add("$changelog.current");
|
||||
}else if(info == versions.first()){
|
||||
in.row();
|
||||
in.add("$text.changelog.latest");
|
||||
in.add("$changelog.latest");
|
||||
}
|
||||
in.row();
|
||||
in.labelWrap("[lightgray]" + desc).width(vw - 20).padTop(12);
|
||||
@@ -77,10 +78,10 @@ public class ChangelogDialog extends FloatingDialog{
|
||||
table.add(in).width(vw).pad(8).row();
|
||||
}
|
||||
|
||||
int lastid = Settings.getInt("lastBuild");
|
||||
int lastid = Core.settings.getInt("lastBuild");
|
||||
if(lastid != 0 && versions.peek().build > lastid){
|
||||
Settings.putInt("lastBuild", versions.peek().build);
|
||||
Settings.save();
|
||||
Core.settings.put("lastBuild", versions.peek().build);
|
||||
Core.settings.save();
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.Dialog;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.ui.Dialog;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.player;
|
||||
import static io.anuke.mindustry.Vars.playerColors;
|
||||
@@ -20,25 +20,25 @@ public class ColorPickDialog extends Dialog{
|
||||
|
||||
private void build(){
|
||||
Table table = new Table();
|
||||
content().add(table);
|
||||
cont.add(table);
|
||||
|
||||
for(int i = 0; i < playerColors.length; i ++){
|
||||
for(int i = 0; i < playerColors.length; i++){
|
||||
Color color = playerColors[i];
|
||||
|
||||
ImageButton button = table.addImageButton("white", "toggle", 34, () -> {
|
||||
ImageButton button = table.addImageButton("white", "clear-toggle", 34, () -> {
|
||||
cons.accept(color);
|
||||
hide();
|
||||
}).size(44, 48).pad(0).padBottom(-5.1f).get();
|
||||
button.setChecked(player.getColor().equals(color));
|
||||
}).size(48).get();
|
||||
button.setChecked(player.color.equals(color));
|
||||
button.getStyle().imageUpColor = color;
|
||||
|
||||
if(i%4 == 3){
|
||||
if(i % 4 == 3){
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
keyDown(key->{
|
||||
if(key == Keys.ESCAPE || key == Keys.BACK)
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK)
|
||||
hide();
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
|
||||
public class ContentInfoDialog extends FloatingDialog{
|
||||
|
||||
public ContentInfoDialog(){
|
||||
super("$info.title");
|
||||
|
||||
addCloseButton();
|
||||
}
|
||||
|
||||
public void show(UnlockableContent content){
|
||||
cont.clear();
|
||||
|
||||
Table table = new Table();
|
||||
table.margin(10);
|
||||
|
||||
content.displayInfo(table);
|
||||
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
cont.add(pane);
|
||||
|
||||
show();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,31 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.KeybindDialog;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.KeybindDialog;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
public class ControlsDialog extends KeybindDialog{
|
||||
|
||||
public ControlsDialog(){
|
||||
setDialog();
|
||||
|
||||
setFillParent(true);
|
||||
title().setAlignment(Align.center);
|
||||
getTitleTable().row();
|
||||
getTitleTable().add(new Image("white"))
|
||||
.growX().height(3f).pad(4f).get().setColor(Colors.get("accent"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCloseButton(){
|
||||
buttons().addImageTextButton("$text.back", "icon-arrow-left", 30f, this::hide).size(230f, 64f);
|
||||
|
||||
keyDown(key->{
|
||||
if(key == Keys.ESCAPE || key == Keys.BACK)
|
||||
hide();
|
||||
});
|
||||
}
|
||||
|
||||
public ControlsDialog(){
|
||||
setStyle(Core.scene.skin.get("dialog", WindowStyle.class));
|
||||
|
||||
setFillParent(true);
|
||||
title.setAlignment(Align.center);
|
||||
titleTable.row();
|
||||
titleTable.add(new Image("white"))
|
||||
.growX().height(3f).pad(4f).get().setColor(Pal.accent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCloseButton(){
|
||||
buttons.addImageTextButton("$back", "icon-arrow-left", 30f, this::hide).size(230f, 64f);
|
||||
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK)
|
||||
hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
76
core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java
Normal file
76
core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.arc.util.Scaling;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class
|
||||
CustomGameDialog extends FloatingDialog{
|
||||
private MapPlayDialog dialog = new MapPlayDialog();
|
||||
|
||||
public CustomGameDialog(){
|
||||
super("$customgame");
|
||||
addCloseButton();
|
||||
shown(this::setup);
|
||||
onResize(this::setup);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
clearChildren();
|
||||
add(titleTable);
|
||||
row();
|
||||
stack(cont, buttons).grow();
|
||||
buttons.bottom();
|
||||
cont.clear();
|
||||
|
||||
Table maps = new Table();
|
||||
maps.marginRight(14);
|
||||
ScrollPane pane = new ScrollPane(maps);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
int maxwidth = (Core.graphics.isPortrait() ? 2 : 4);
|
||||
float images = 146f;
|
||||
|
||||
int i = 0;
|
||||
maps.defaults().width(170).fillY().top().pad(4f);
|
||||
for(Map map : world.maps.all()){
|
||||
|
||||
if(i % maxwidth == 0){
|
||||
maps.row();
|
||||
}
|
||||
|
||||
ImageButton image = new ImageButton(new TextureRegion(map.texture), "clear");
|
||||
image.margin(5);
|
||||
image.getImageCell().size(images);
|
||||
image.top();
|
||||
image.row();
|
||||
image.add("[accent]" + map.name()).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center);
|
||||
image.row();
|
||||
image.label((() -> Core.bundle.format("level.highscore", map.getHightScore()))).pad(3f);
|
||||
|
||||
BorderImage border = new BorderImage(map.texture, 3f);
|
||||
border.setScaling(Scaling.fit);
|
||||
image.replaceImage(border);
|
||||
|
||||
image.clicked(() -> dialog.show(map));
|
||||
|
||||
maps.add(image);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if(world.maps.all().size == 0){
|
||||
maps.add("$maps.none").pad(50);
|
||||
}
|
||||
|
||||
cont.add(pane).uniformX();
|
||||
}
|
||||
}
|
||||
106
core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java
Normal file
106
core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java
Normal file
@@ -0,0 +1,106 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class CustomRulesDialog extends FloatingDialog{
|
||||
private Table main;
|
||||
private Rules rules;
|
||||
private Supplier<Rules> resetter;
|
||||
|
||||
public CustomRulesDialog(){
|
||||
super("$mode.custom");
|
||||
|
||||
setFillParent(true);
|
||||
shown(this::setup);
|
||||
addCloseButton();
|
||||
}
|
||||
|
||||
public void show(Rules rules, Supplier<Rules> resetter){
|
||||
this.rules = rules;
|
||||
this.resetter = resetter;
|
||||
show();
|
||||
}
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
cont.pane(m -> main = m);
|
||||
main.margin(10f);
|
||||
main.addButton("$settings.reset", () -> {
|
||||
rules = resetter.get();
|
||||
setup();
|
||||
}).size(300f, 50f);
|
||||
main.left().defaults().fillX().left().pad(5);
|
||||
main.row();
|
||||
|
||||
title("$rules.title.waves");
|
||||
check("$rules.waves", b -> rules.waves = b, () -> rules.waves);
|
||||
check("$rules.wavetimer", b -> rules.waveTimer = b, () -> rules.waveTimer);
|
||||
check("$rules.waitForWaveToEnd", b -> rules.waitForWaveToEnd = b, () -> rules.waitForWaveToEnd);
|
||||
number("$rules.wavespacing", false, f -> rules.waveSpacing = f * 60f, () -> rules.waveSpacing / 60f, () -> true);
|
||||
number("$rules.dropzoneradius", false, f -> rules.dropZoneRadius = f * tilesize, () -> rules.dropZoneRadius / tilesize, () -> true);
|
||||
|
||||
title("$rules.title.respawns");
|
||||
check("$rules.limitedRespawns", b -> rules.limitedRespawns = b, () -> rules.limitedRespawns);
|
||||
number("$rules.respawns", true, f -> rules.respawns = (int)f, () -> rules.respawns, () -> rules.limitedRespawns);
|
||||
number("$rules.respawntime", f -> rules.respawnTime = f * 60f, () -> rules.respawnTime / 60f);
|
||||
|
||||
title("$rules.title.resourcesbuilding");
|
||||
check("$rules.infiniteresources", b -> rules.infiniteResources = b, () -> rules.infiniteResources);
|
||||
number("$rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
|
||||
number("$rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier);
|
||||
|
||||
title("$rules.title.player");
|
||||
number("$rules.playerdamagemultiplier", f -> rules.playerDamageMultiplier = f, () -> rules.playerDamageMultiplier);
|
||||
number("$rules.playerhealthmultiplier", f -> rules.playerHealthMultiplier = f, () -> rules.playerHealthMultiplier);
|
||||
|
||||
title("$rules.title.unit");
|
||||
check("$rules.unitdrops", b -> rules.unitDrops = b, () -> rules.unitDrops, () -> true);
|
||||
number("$rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier);
|
||||
number("$rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier);
|
||||
number("$rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
|
||||
|
||||
title("$rules.title.enemy");
|
||||
check("$rules.attack", b -> rules.attackMode = b, () -> rules.attackMode);
|
||||
check("$rules.enemyCheat", b -> rules.enemyCheat = b, () -> rules.enemyCheat);
|
||||
number("$rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200));
|
||||
}
|
||||
|
||||
void number(String text, FloatConsumer cons, FloatProvider prov){
|
||||
number(text, false, cons, prov, () -> true);
|
||||
}
|
||||
|
||||
void number(String text, boolean integer, FloatConsumer cons, FloatProvider prov, BooleanProvider condition){
|
||||
main.table(t -> {
|
||||
t.left();
|
||||
t.add(text).left().padRight(5)
|
||||
.update(a -> a.setColor(condition.get() ? Color.WHITE : Color.GRAY));
|
||||
Platform.instance.addDialog(t.addField((integer ? (int)prov.get() : prov.get()) + "", s -> cons.accept(Strings.parseFloat(s)))
|
||||
.padRight(100f)
|
||||
.update(a -> a.setDisabled(!condition.get()))
|
||||
.valid(Strings::canParsePositiveFloat).width(120f).left().get());
|
||||
}).padTop(0);
|
||||
main.row();
|
||||
}
|
||||
|
||||
void check(String text, BooleanConsumer cons, BooleanProvider prov){
|
||||
check(text, cons, prov, () -> true);
|
||||
}
|
||||
|
||||
void check(String text, BooleanConsumer cons, BooleanProvider prov, BooleanProvider condition){
|
||||
main.addCheck(text, cons).checked(prov.get()).update(a -> a.setDisabled(!condition.get())).padRight(100f).get().left();
|
||||
main.row();
|
||||
}
|
||||
|
||||
void title(String text){
|
||||
main.add(text).color(Pal.accent).padTop(20).padBottom(20).padRight(100f);
|
||||
main.row();
|
||||
}
|
||||
}
|
||||
79
core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java
Normal file
79
core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.scene.event.HandCursorListener;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
|
||||
public class DatabaseDialog extends FloatingDialog{
|
||||
|
||||
public DatabaseDialog(){
|
||||
super("$database");
|
||||
|
||||
shouldPause = true;
|
||||
addCloseButton();
|
||||
shown(this::rebuild);
|
||||
onResize(this::rebuild);
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
cont.clear();
|
||||
|
||||
Table table = new Table();
|
||||
table.margin(20);
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
|
||||
Array<Content>[] allContent = Vars.content.getContentMap();
|
||||
|
||||
for(int j = 0; j < allContent.length; j++){
|
||||
ContentType type = ContentType.values()[j];
|
||||
|
||||
Array<Content> array = allContent[j].select(c -> c instanceof UnlockableContent && !((UnlockableContent)c).isHidden());
|
||||
if(array.size == 0) continue;
|
||||
|
||||
table.add("$content." + type.name() + ".name").growX().left().color(Pal.accent);
|
||||
table.row();
|
||||
table.addImage("white").growX().pad(5).padLeft(0).padRight(0).height(3).color(Pal.accent);
|
||||
table.row();
|
||||
table.table(list -> {
|
||||
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.addListener(new HandCursorListener());
|
||||
list.add(image).size(size).pad(3);
|
||||
|
||||
if(unlocked(unlock)){
|
||||
image.clicked(() -> Vars.ui.content.show(unlock));
|
||||
image.addListener(new Tooltip(t -> t.background("button").add(unlock.localizedName())));
|
||||
}
|
||||
|
||||
if((++count) % maxWidth == 0){
|
||||
list.row();
|
||||
}
|
||||
}
|
||||
}).growX().left().padBottom(10);
|
||||
table.row();
|
||||
}
|
||||
|
||||
cont.add(pane);
|
||||
}
|
||||
|
||||
boolean unlocked(UnlockableContent content){
|
||||
return (!Vars.world.isZone() && !Vars.state.is(State.menu)) || content.unlocked();
|
||||
}
|
||||
}
|
||||
202
core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java
Normal file
202
core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java
Normal file
@@ -0,0 +1,202 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.collection.ObjectSet.ObjectSetIterator;
|
||||
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.util.Align;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.content.Zones;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.Saves.SaveSlot;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.io.SaveIO.SaveException;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.type.Zone.ZoneRequirement;
|
||||
import io.anuke.mindustry.ui.ItemsDisplay;
|
||||
import io.anuke.mindustry.ui.TreeLayout;
|
||||
import io.anuke.mindustry.ui.TreeLayout.TreeNode;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class DeployDialog extends FloatingDialog{
|
||||
private final float nodeSize = Unit.dp.scl(210f);
|
||||
private ObjectSet<ZoneNode> nodes = new ObjectSet<>();
|
||||
private ZoneInfoDialog info = new ZoneInfoDialog();
|
||||
|
||||
public DeployDialog(){
|
||||
super("");
|
||||
|
||||
ZoneNode root = new ZoneNode(Zones.groundZero, null);
|
||||
|
||||
TreeLayout layout = new TreeLayout();
|
||||
layout.gapBetweenLevels = layout.gapBetweenNodes = Unit.dp.scl(50f);
|
||||
layout.layout(root);
|
||||
|
||||
addCloseButton();
|
||||
buttons.addImageTextButton("$techtree", "icon-tree", iconsize, () -> ui.tech.show()).size(230f, 64f);
|
||||
|
||||
shown(this::setup);
|
||||
}
|
||||
|
||||
public void setup(){
|
||||
cont.clear();
|
||||
titleTable.remove();
|
||||
margin(0f).marginBottom(8);
|
||||
|
||||
if(!Core.settings.getBool("zone-info", false)){
|
||||
Core.app.post(() -> ui.showInfoText("TEMPORARY GUIDE ON HOW TO PLAY ZONES", "- deploy to zones by selecting them here\n- most zones require items to deploy\n- once you survive a set amount of waves, you can launch all the resources in your core\n- use these items to research in the tech tree or uncover new zones"));
|
||||
|
||||
Core.settings.put("zone-info", true);
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
cont.stack(control.saves.getZoneSlot() == null ? new View() : new Table(){{
|
||||
SaveSlot slot = control.saves.getZoneSlot();
|
||||
|
||||
TextButton[] b = {null};
|
||||
|
||||
TextButton button = addButton(Core.bundle.format("resume", slot.getZone().localizedName()), () -> {
|
||||
if(b[0].childrenPressed()) return;
|
||||
|
||||
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;
|
||||
|
||||
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.addButton("$abandon", () -> {
|
||||
ui.showConfirm("$warning", "$abandon.text", () -> {
|
||||
slot.delete();
|
||||
setup();
|
||||
});
|
||||
}).growX().height(50f).pad(-12).padTop(10);
|
||||
|
||||
}}, new ItemsDisplay()).grow();
|
||||
|
||||
//set up direct and indirect children
|
||||
for(ZoneNode node : nodes){
|
||||
node.allChildren.clear();
|
||||
node.allChildren.addAll(node.children);
|
||||
for(ZoneNode other : new ObjectSetIterator<>(nodes)){
|
||||
if(Structs.contains(other.zone.zoneRequirements, req -> req.zone == node.zone)){
|
||||
node.allChildren.add(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean hidden(Zone zone){
|
||||
for(ZoneRequirement other : zone.zoneRequirements){
|
||||
if(!data.isUnlocked(other.zone)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(float x, float y){
|
||||
drawDefaultBackground(x, y);
|
||||
}
|
||||
|
||||
void buildButton(Zone zone, TextButton button){
|
||||
button.setDisabled(() -> hidden(zone));
|
||||
button.clicked(() -> info.show(zone));
|
||||
|
||||
if(zone.unlocked()){
|
||||
button.addImage("icon-terrain").size(iconsize).padRight(3);
|
||||
button.labelWrap(zone.localizedName()).width(140).growX();
|
||||
}else{
|
||||
button.addImage("icon-locked");
|
||||
button.row();
|
||||
button.add("$locked");
|
||||
}
|
||||
}
|
||||
|
||||
//should be static variables of View, but that's impossible
|
||||
static float panX = 0, panY = -200;
|
||||
|
||||
class View extends Group{
|
||||
|
||||
{
|
||||
for(ZoneNode node : nodes){
|
||||
TextButton button = new TextButton("", "node");
|
||||
button.setSize(node.width, node.height);
|
||||
button.update(() -> {
|
||||
button.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f, Align.center);
|
||||
});
|
||||
button.clearChildren();
|
||||
buildButton(node.zone, button);
|
||||
addChild(button);
|
||||
}
|
||||
|
||||
dragged((x, y) -> {
|
||||
panX += x;
|
||||
panY += y;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float offsetX = panX + width / 2f + x, offsetY = panY + height / 2f + y;
|
||||
|
||||
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.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
|
||||
class ZoneNode extends TreeNode<ZoneNode>{
|
||||
final Array<Zone> arr = new Array<>();
|
||||
final Array<ZoneNode> allChildren = new Array<>();
|
||||
final Zone zone;
|
||||
|
||||
ZoneNode(Zone zone, ZoneNode parent){
|
||||
this.zone = zone;
|
||||
this.parent = parent;
|
||||
this.width = this.height = nodeSize;
|
||||
this.height /= 2f;
|
||||
nodes.add(this);
|
||||
|
||||
arr.selectFrom(content.zones(), other -> other.zoneRequirements.length > 0 && other.zoneRequirements[0].zone == zone);
|
||||
|
||||
children = new ZoneNode[arr.size];
|
||||
for(int i = 0; i < children.length; i++){
|
||||
children[i] = new ZoneNode(arr.get(i), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,24 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import io.anuke.ucore.scene.ui.Dialog;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.Dialog;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
import static io.anuke.mindustry.Vars.discordURL;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class DiscordDialog extends Dialog {
|
||||
public class DiscordDialog extends Dialog{
|
||||
|
||||
public DiscordDialog(){
|
||||
super("", "dialog");
|
||||
|
||||
float h = 70f;
|
||||
|
||||
content().margin(12f);
|
||||
cont.margin(12f);
|
||||
|
||||
Color color = Color.valueOf("7289da");
|
||||
|
||||
content().table(t -> {
|
||||
cont.table(t -> {
|
||||
t.background("button").margin(0);
|
||||
|
||||
t.table(img -> {
|
||||
@@ -30,22 +29,22 @@ public class DiscordDialog extends Dialog {
|
||||
|
||||
t.table(i -> {
|
||||
i.background("button");
|
||||
i.addImage("icon-discord").size(14 * 3);
|
||||
i.addImage("icon-discord").size(iconsize);
|
||||
}).size(h).left();
|
||||
|
||||
t.add("$text.discord").color(Colors.get("accent")).growX().padLeft(10f);
|
||||
}).size(470f, h).pad(10f);
|
||||
t.add("$discord").color(Pal.accent).growX().padLeft(10f);
|
||||
}).size(440f, h).pad(10f);
|
||||
|
||||
buttons().defaults().size(170f, 50);
|
||||
buttons.defaults().size(150f, 50);
|
||||
|
||||
buttons().addButton("$text.back", this::hide);
|
||||
buttons().addButton("$text.copylink", () ->{
|
||||
Gdx.app.getClipboard().setContents(discordURL);
|
||||
buttons.addButton("$back", this::hide);
|
||||
buttons.addButton("$copylink", () -> {
|
||||
Core.app.getClipboard().setContents(discordURL);
|
||||
});
|
||||
buttons().addButton("$text.openlink", () ->{
|
||||
if(!Gdx.net.openURI(discordURL)){
|
||||
ui.showError("$text.linkfail");
|
||||
Gdx.app.getClipboard().setContents(discordURL);
|
||||
buttons.addButton("$openlink", () -> {
|
||||
if(!Core.net.openURI(discordURL)){
|
||||
ui.showError("$linkfail");
|
||||
Core.app.getClipboard().setContents(discordURL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,337 +1,340 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Pools;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.graphics.g2d.GlyphLayout;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.ucore.UCore;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.function.Predicate;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.*;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FileChooser extends FloatingDialog {
|
||||
private Table files;
|
||||
private FileHandle homeDirectory = Gdx.files.absolute(OS.isMac ? UCore.getProperty("user.home") + "/Downloads/" :
|
||||
Gdx.files.getExternalStoragePath());
|
||||
private FileHandle directory = homeDirectory;
|
||||
private ScrollPane pane;
|
||||
private TextField navigation, filefield;
|
||||
private TextButton ok;
|
||||
private FileHistory stack = new FileHistory();
|
||||
private Predicate<FileHandle> filter;
|
||||
private Consumer<FileHandle> selectListener;
|
||||
private boolean open;
|
||||
|
||||
public FileChooser(String title, boolean open, Consumer<FileHandle> result){
|
||||
this(title, defaultFilter, open, result);
|
||||
}
|
||||
import static io.anuke.mindustry.Vars.iconsize;
|
||||
|
||||
public FileChooser(String title, Predicate<FileHandle> filter, boolean open, Consumer<FileHandle> result){
|
||||
super(title);
|
||||
this.open = open;
|
||||
this.filter = filter;
|
||||
this.selectListener = result;
|
||||
}
|
||||
public class FileChooser extends FloatingDialog{
|
||||
private static final FileHandle homeDirectory = Core.files.absolute(OS.isMac ? OS.getProperty("user.home") + "/Downloads/" : Core.files.getExternalStoragePath());
|
||||
private static FileHandle lastDirectory = homeDirectory;
|
||||
|
||||
private void setupWidgets(){
|
||||
getCell(content()).maxWidth(Gdx.graphics.getWidth()/Unit.dp.scl(2f));
|
||||
content().margin(-10);
|
||||
|
||||
Table content = new Table();
|
||||
|
||||
filefield = new TextField();
|
||||
filefield.setOnlyFontChars(false);
|
||||
if(!open) Platform.instance.addDialog(filefield);
|
||||
filefield.setDisabled(open);
|
||||
private Table files;
|
||||
private FileHandle directory = lastDirectory;
|
||||
private ScrollPane pane;
|
||||
private TextField navigation, filefield;
|
||||
private TextButton ok;
|
||||
private FileHistory stack = new FileHistory();
|
||||
private Predicate<FileHandle> filter;
|
||||
private Consumer<FileHandle> selectListener;
|
||||
private boolean open;
|
||||
private int lastWidth = Core.graphics.getWidth(), lastHeight = Core.graphics.getHeight();
|
||||
|
||||
ok = new TextButton(open ? "$text.load" : "$text.save");
|
||||
|
||||
ok.clicked(() -> {
|
||||
if(ok.isDisabled()) return;
|
||||
if(selectListener != null)
|
||||
selectListener.accept(directory.child(filefield.getText()));
|
||||
hide();
|
||||
});
|
||||
|
||||
filefield.changed(() -> {
|
||||
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
|
||||
});
|
||||
|
||||
filefield.change();
|
||||
|
||||
TextButton cancel = new TextButton("$text.cancel");
|
||||
cancel.clicked(this::hide);
|
||||
public static final Predicate<String> pngFiles = str -> str.equals("png");
|
||||
public static final Predicate<String> anyMapFiles = str -> str.equals(Vars.oldMapExtension) || str.equals(Vars.mapExtension);
|
||||
public static final Predicate<String> mapFiles = str -> str.equals(Vars.mapExtension);
|
||||
public static final Predicate<String> saveFiles = str -> str.equals(Vars.saveExtension);
|
||||
|
||||
navigation = new TextField("");
|
||||
navigation.setTouchable(Touchable.disabled);
|
||||
public FileChooser(String title, Predicate<FileHandle> filter, boolean open, Consumer<FileHandle> result){
|
||||
super(title);
|
||||
this.open = open;
|
||||
this.filter = filter;
|
||||
this.selectListener = result;
|
||||
|
||||
files = new Table();
|
||||
update(() -> {
|
||||
if(Core.graphics.getWidth() != lastWidth || Core.graphics.getHeight() != lastHeight){
|
||||
updateFiles(false);
|
||||
lastHeight = Core.graphics.getHeight();
|
||||
lastWidth = Core.graphics.getWidth();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pane = new ScrollPane(files){
|
||||
public float getPrefHeight(){
|
||||
return Gdx.graphics.getHeight();
|
||||
}
|
||||
};
|
||||
pane.setOverscroll(false, false);
|
||||
pane.setFadeScrollBars(false);
|
||||
private void setupWidgets(){
|
||||
cont.margin(-10);
|
||||
|
||||
updateFiles(true);
|
||||
Table content = new Table();
|
||||
|
||||
Table icontable = new Table();
|
||||
|
||||
float isize = 14*2;
|
||||
filefield = new TextField();
|
||||
filefield.setOnlyFontChars(false);
|
||||
if(!open) Platform.instance.addDialog(filefield);
|
||||
filefield.setDisabled(open);
|
||||
|
||||
ImageButton up = new ImageButton("icon-folder-parent");
|
||||
up.resizeImage(isize);
|
||||
up.clicked(()->{
|
||||
directory = directory.parent();
|
||||
updateFiles(true);
|
||||
});
|
||||
ok = new TextButton(open ? "$load" : "$save");
|
||||
|
||||
//Macs are confined to the Downloads/ directory
|
||||
if(OS.isMac){
|
||||
up.setDisabled(true);
|
||||
}
|
||||
ok.clicked(() -> {
|
||||
if(ok.isDisabled()) return;
|
||||
if(selectListener != null)
|
||||
selectListener.accept(directory.child(filefield.getText()));
|
||||
hide();
|
||||
});
|
||||
|
||||
ImageButton back = new ImageButton("icon-arrow-left");
|
||||
back.resizeImage(isize);
|
||||
|
||||
ImageButton forward = new ImageButton("icon-arrow-right");
|
||||
forward.resizeImage(isize);
|
||||
|
||||
forward.clicked(()-> stack.forward());
|
||||
|
||||
back.clicked(()-> stack.back());
|
||||
|
||||
ImageButton home = new ImageButton("icon-home");
|
||||
home.resizeImage(isize);
|
||||
home.clicked(()->{
|
||||
directory = homeDirectory;
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
icontable.defaults().height(50).growX().uniform();
|
||||
icontable.add(home);
|
||||
icontable.add(back);
|
||||
icontable.add(forward);
|
||||
icontable.add(up);
|
||||
|
||||
Table fieldcontent = new Table();
|
||||
fieldcontent.bottom().left().add(new Label("File Name:"));
|
||||
fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f);
|
||||
|
||||
Table buttons = new Table();
|
||||
buttons.defaults().growX().height(50);
|
||||
buttons.add(cancel);
|
||||
buttons.add(ok);
|
||||
|
||||
content.top().left();
|
||||
content.add(icontable).expandX().fillX();
|
||||
content.row();
|
||||
filefield.changed(() -> {
|
||||
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
|
||||
});
|
||||
|
||||
content.center().add(pane).width(Gdx.graphics.getWidth()/Unit.dp.scl(2)).colspan(3).grow();
|
||||
content.row();
|
||||
|
||||
if(!open){
|
||||
content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2);
|
||||
content.row();
|
||||
}
|
||||
filefield.change();
|
||||
|
||||
content.add(buttons).growX();
|
||||
|
||||
content().add(content);
|
||||
}
|
||||
|
||||
private void updateFileFieldStatus(){
|
||||
if(!open){
|
||||
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
|
||||
}else{
|
||||
ok.setDisabled(!directory.child(filefield.getText()).exists() || directory.child(filefield.getText()).isDirectory());
|
||||
}
|
||||
}
|
||||
TextButton cancel = new TextButton("$cancel");
|
||||
cancel.clicked(this::hide);
|
||||
|
||||
private FileHandle[] getFileNames(){
|
||||
FileHandle[] handles = directory.list(file -> !file.getName().startsWith("."));
|
||||
navigation = new TextField("");
|
||||
navigation.touchable(Touchable.disabled);
|
||||
|
||||
Arrays.sort(handles, (a, b) ->{
|
||||
if(a.isDirectory() && !b.isDirectory()) return -1;
|
||||
if( !a.isDirectory() && b.isDirectory()) return 1;
|
||||
return a.name().toUpperCase().compareTo(b.name().toUpperCase());
|
||||
});
|
||||
return handles;
|
||||
}
|
||||
files = new Table();
|
||||
files.marginRight(10);
|
||||
files.marginLeft(3);
|
||||
|
||||
private void updateFiles(boolean push){
|
||||
if(push) stack.push(directory);
|
||||
//if is mac, don't display extra info since you can only ever go to downloads
|
||||
navigation.setText(OS.isMac ? directory.name() : directory.toString());
|
||||
|
||||
GlyphLayout layout = Pools.obtain(GlyphLayout.class);
|
||||
|
||||
layout.setText(Core.font, navigation.getText());
|
||||
|
||||
if(layout.width < navigation.getWidth()){
|
||||
navigation.setCursorPosition(0);
|
||||
}else{
|
||||
navigation.setCursorPosition(navigation.getText().length());
|
||||
}
|
||||
|
||||
Pools.free(layout);
|
||||
pane = new ScrollPane(files){
|
||||
public float getPrefHeight(){
|
||||
return Core.graphics.getHeight();
|
||||
}
|
||||
};
|
||||
pane.setOverscroll(false, false);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
files.clearChildren();
|
||||
files.top().left();
|
||||
FileHandle[] names = getFileNames();
|
||||
updateFiles(true);
|
||||
|
||||
//macs are confined to the Downloads/ directory
|
||||
if(!OS.isMac) {
|
||||
Image upimage = new Image("icon-folder-parent");
|
||||
TextButton upbutton = new TextButton(".." + directory.toString());
|
||||
upbutton.clicked(() -> {
|
||||
directory = directory.parent();
|
||||
updateFiles(true);
|
||||
});
|
||||
Table icontable = new Table();
|
||||
|
||||
upbutton.left().add(upimage).padRight(4f).size(14 * 2);
|
||||
upbutton.getLabel().setAlignment(Align.left);
|
||||
upbutton.getCells().reverse();
|
||||
float isize = iconsize;
|
||||
|
||||
files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2);
|
||||
files.row();
|
||||
}
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<TextButton>();
|
||||
group.setMinCheckCount(0);
|
||||
ImageButton up = new ImageButton("icon-folder-parent");
|
||||
up.resizeImage(isize);
|
||||
up.clicked(() -> {
|
||||
directory = directory.parent();
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
for(FileHandle file : names){
|
||||
if( !file.isDirectory() && !filter.test(file)) continue; //skip non-filtered files
|
||||
//Macs are confined to the Downloads/ directory
|
||||
if(OS.isMac){
|
||||
up.setDisabled(true);
|
||||
}
|
||||
|
||||
String filename = file.name();
|
||||
ImageButton back = new ImageButton("icon-arrow-left");
|
||||
back.resizeImage(isize);
|
||||
|
||||
TextButton button = new TextButton(shorten(filename), "toggle");
|
||||
group.add(button);
|
||||
|
||||
button.clicked(()->{
|
||||
if( !file.isDirectory()){
|
||||
filefield.setText(filename);
|
||||
updateFileFieldStatus();
|
||||
}else{
|
||||
directory = directory.child(filename);
|
||||
updateFiles(true);
|
||||
}
|
||||
});
|
||||
|
||||
filefield.changed(()->{
|
||||
button.setChecked(filename.equals(filefield.getText()));
|
||||
});
|
||||
|
||||
Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text");
|
||||
|
||||
button.add(image).padRight(4f).size(14*2f);
|
||||
button.getCells().reverse();
|
||||
files.top().left().add(button).align(Align.topLeft).fillX().expandX()
|
||||
.height(50).pad(2).padTop(0).padBottom(0).colspan(2);
|
||||
button.getLabel().setAlignment(Align.left);
|
||||
files.row();
|
||||
}
|
||||
ImageButton forward = new ImageButton("icon-arrow-right");
|
||||
forward.resizeImage(isize);
|
||||
|
||||
pane.setScrollY(0f);
|
||||
updateFileFieldStatus();
|
||||
|
||||
if(open) filefield.clearText();
|
||||
}
|
||||
forward.clicked(() -> stack.forward());
|
||||
|
||||
private String shorten(String string){
|
||||
int max = 30;
|
||||
if(string.length() <= max){
|
||||
return string;
|
||||
}else{
|
||||
return string.substring(0, max - 3).concat("...");
|
||||
}
|
||||
}
|
||||
back.clicked(() -> stack.back());
|
||||
|
||||
@Override
|
||||
public Dialog show(){
|
||||
Platform.instance.requestWritePerms();
|
||||
Timers.runTask(2f, () -> {
|
||||
content().clear();
|
||||
setupWidgets();
|
||||
super.show();
|
||||
Core.scene.setScrollFocus(pane);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
ImageButton home = new ImageButton("icon-home");
|
||||
home.resizeImage(isize);
|
||||
home.clicked(() -> {
|
||||
directory = homeDirectory;
|
||||
lastDirectory = directory;
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
public void fileSelected(Consumer<FileHandle> listener){
|
||||
this.selectListener = listener;
|
||||
}
|
||||
icontable.defaults().height(60).growX().padTop(5).uniform();
|
||||
icontable.add(home);
|
||||
icontable.add(back);
|
||||
icontable.add(forward);
|
||||
icontable.add(up);
|
||||
|
||||
public class FileHistory{
|
||||
private Array<FileHandle> history = new Array<FileHandle>();
|
||||
private int index;
|
||||
Table fieldcontent = new Table();
|
||||
fieldcontent.bottom().left().add(new Label("$filename"));
|
||||
fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f);
|
||||
|
||||
public FileHistory(){
|
||||
Table buttons = new Table();
|
||||
buttons.defaults().growX().height(60);
|
||||
buttons.add(cancel);
|
||||
buttons.add(ok);
|
||||
|
||||
}
|
||||
content.top().left();
|
||||
content.add(icontable).expandX().fillX();
|
||||
content.row();
|
||||
|
||||
public void push(FileHandle file){
|
||||
if(index != history.size) history.truncate(index);
|
||||
history.add(file);
|
||||
index ++;
|
||||
}
|
||||
content.center().add(pane).width(Core.graphics.isPortrait() ? Core.graphics.getWidth() / Unit.dp.scl(1) : Core.graphics.getWidth() / Unit.dp.scl(2)).colspan(3).grow();
|
||||
content.row();
|
||||
|
||||
public void back(){
|
||||
if( !canBack()) return;
|
||||
index --;
|
||||
directory = history.get(index - 1);
|
||||
updateFiles(false);
|
||||
}
|
||||
if(!open){
|
||||
content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2);
|
||||
content.row();
|
||||
}
|
||||
|
||||
public void forward(){
|
||||
if( !canForward()) return;
|
||||
directory = history.get(index);
|
||||
index ++;
|
||||
updateFiles(false);
|
||||
}
|
||||
content.add(buttons).growX();
|
||||
|
||||
public boolean canForward(){
|
||||
return !(index >= history.size);
|
||||
}
|
||||
cont.add(content);
|
||||
}
|
||||
|
||||
public boolean canBack(){
|
||||
return !(index == 1) && index > 0;
|
||||
}
|
||||
private void updateFileFieldStatus(){
|
||||
if(!open){
|
||||
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
|
||||
}else{
|
||||
ok.setDisabled(!directory.child(filefield.getText()).exists() || directory.child(filefield.getText()).isDirectory());
|
||||
}
|
||||
}
|
||||
|
||||
void print(){
|
||||
private FileHandle[] getFileNames(){
|
||||
FileHandle[] handles = directory.list(file -> !file.getName().startsWith("."));
|
||||
|
||||
System.out.println("\n\n\n\n\n\n");
|
||||
int i = 0;
|
||||
for(FileHandle file : history){
|
||||
i ++;
|
||||
if(index == i){
|
||||
System.out.println("[[" + file.toString() + "]]");
|
||||
}else{
|
||||
System.out.println("--" + file.toString() + "--");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Arrays.sort(handles, (a, b) -> {
|
||||
if(a.isDirectory() && !b.isDirectory()) return -1;
|
||||
if(!a.isDirectory() && b.isDirectory()) return 1;
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(a.name(), b.name());
|
||||
});
|
||||
return handles;
|
||||
}
|
||||
|
||||
public interface FileHandleFilter{
|
||||
boolean accept(FileHandle file);
|
||||
}
|
||||
private void updateFiles(boolean push){
|
||||
if(push) stack.push(directory);
|
||||
//if is mac, don't display extra info since you can only ever go to downloads
|
||||
navigation.setText(OS.isMac ? directory.name() : directory.toString());
|
||||
|
||||
public static Predicate<FileHandle> pngFilter = file -> file.extension().equalsIgnoreCase("png");
|
||||
public static Predicate<FileHandle> jpegFilter = file -> file.extension().equalsIgnoreCase("png") || file.extension().equalsIgnoreCase("jpg") || file.extension().equalsIgnoreCase("jpeg");
|
||||
public static Predicate<FileHandle> defaultFilter = file -> true;
|
||||
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
|
||||
layout.setText(Core.scene.skin.getFont("default-font"), navigation.getText());
|
||||
|
||||
if(layout.width < navigation.getWidth()){
|
||||
navigation.setCursorPosition(0);
|
||||
}else{
|
||||
navigation.setCursorPosition(navigation.getText().length());
|
||||
}
|
||||
|
||||
Pools.free(layout);
|
||||
|
||||
files.clearChildren();
|
||||
files.top().left();
|
||||
FileHandle[] names = getFileNames();
|
||||
|
||||
//macs are confined to the Downloads/ directory
|
||||
if(!OS.isMac){
|
||||
Image upimage = new Image("icon-folder-parent");
|
||||
TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle");
|
||||
upbutton.clicked(() -> {
|
||||
directory = directory.parent();
|
||||
lastDirectory = directory;
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
upbutton.left().add(upimage).padRight(4f).size(iconsize);
|
||||
upbutton.getLabel().setAlignment(Align.left);
|
||||
upbutton.getCells().reverse();
|
||||
|
||||
files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2);
|
||||
files.row();
|
||||
}
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
group.setMinCheckCount(0);
|
||||
|
||||
for(FileHandle file : names){
|
||||
if(!file.isDirectory() && !filter.test(file)) continue; //skip non-filtered files
|
||||
|
||||
String filename = file.name();
|
||||
|
||||
TextButton button = new TextButton(shorten(filename), "clear-toggle");
|
||||
group.add(button);
|
||||
|
||||
button.clicked(() -> {
|
||||
if(!file.isDirectory()){
|
||||
filefield.setText(filename);
|
||||
updateFileFieldStatus();
|
||||
}else{
|
||||
directory = directory.child(filename);
|
||||
lastDirectory = directory;
|
||||
updateFiles(true);
|
||||
}
|
||||
});
|
||||
|
||||
filefield.changed(() -> {
|
||||
button.setChecked(filename.equals(filefield.getText()));
|
||||
});
|
||||
|
||||
Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text");
|
||||
|
||||
button.add(image).padRight(4f).size(iconsize);
|
||||
button.getCells().reverse();
|
||||
files.top().left().add(button).align(Align.topLeft).fillX().expandX()
|
||||
.height(50).pad(2).padTop(0).padBottom(0).colspan(2);
|
||||
button.getLabel().setAlignment(Align.left);
|
||||
files.row();
|
||||
}
|
||||
|
||||
pane.setScrollY(0f);
|
||||
updateFileFieldStatus();
|
||||
|
||||
if(open) filefield.clearText();
|
||||
}
|
||||
|
||||
private String shorten(String string){
|
||||
int max = 30;
|
||||
if(string.length() <= max){
|
||||
return string;
|
||||
}else{
|
||||
return string.substring(0, max - 3).concat("...");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog show(){
|
||||
Time.runTask(2f, () -> {
|
||||
cont.clear();
|
||||
setupWidgets();
|
||||
super.show();
|
||||
Core.scene.setScrollFocus(pane);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public class FileHistory{
|
||||
private Array<FileHandle> history = new Array<>();
|
||||
private int index;
|
||||
|
||||
public FileHistory(){
|
||||
|
||||
}
|
||||
|
||||
public void push(FileHandle file){
|
||||
if(index != history.size) history.truncate(index);
|
||||
history.add(file);
|
||||
index++;
|
||||
}
|
||||
|
||||
public void back(){
|
||||
if(!canBack()) return;
|
||||
index--;
|
||||
directory = history.get(index - 1);
|
||||
lastDirectory = directory;
|
||||
updateFiles(false);
|
||||
}
|
||||
|
||||
public void forward(){
|
||||
if(!canForward()) return;
|
||||
directory = history.get(index);
|
||||
lastDirectory = directory;
|
||||
index++;
|
||||
updateFiles(false);
|
||||
}
|
||||
|
||||
public boolean canForward(){
|
||||
return !(index >= history.size);
|
||||
}
|
||||
|
||||
public boolean canBack(){
|
||||
return !(index == 1) && index > 0;
|
||||
}
|
||||
|
||||
void print(){
|
||||
|
||||
System.out.println("\n\n\n\n\n\n");
|
||||
int i = 0;
|
||||
for(FileHandle file : history){
|
||||
i++;
|
||||
if(index == i){
|
||||
System.out.println("[[" + file.toString() + "]]");
|
||||
}else{
|
||||
System.out.println("--" + file.toString() + "--");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,75 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.ucore.scene.ui.Dialog;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.ui.Dialog;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.ResizeEvent;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
import static io.anuke.mindustry.Vars.iconsize;
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
|
||||
public class FloatingDialog extends Dialog{
|
||||
|
||||
public FloatingDialog(String title){
|
||||
super(title, "dialog");
|
||||
setFillParent(true);
|
||||
title().setAlignment(Align.center);
|
||||
getTitleTable().row();
|
||||
getTitleTable().addImage("white", Colors.get("accent"))
|
||||
.growX().height(3f).pad(4f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCloseButton(){
|
||||
buttons().addImageTextButton("$text.back", "icon-arrow-left", 30f, this::hide).size(230f, 64f);
|
||||
|
||||
keyDown(key->{
|
||||
if(key == Keys.ESCAPE || key == Keys.BACK)
|
||||
hide();
|
||||
});
|
||||
}
|
||||
private boolean wasPaused;
|
||||
protected boolean shouldPause;
|
||||
|
||||
public FloatingDialog(String title){
|
||||
super(title, "dialog");
|
||||
setFillParent(true);
|
||||
this.title.setAlignment(Align.center);
|
||||
titleTable.row();
|
||||
titleTable.addImage("white", Pal.accent)
|
||||
.growX().height(3f).pad(4f);
|
||||
|
||||
hidden(() -> {
|
||||
if(shouldPause && !state.is(State.menu)){
|
||||
if(!wasPaused || Net.active()){
|
||||
state.set(State.playing);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
shown(() -> {
|
||||
if(shouldPause && !state.is(State.menu)){
|
||||
wasPaused = state.is(State.paused);
|
||||
state.set(State.paused);
|
||||
}
|
||||
});
|
||||
|
||||
boolean[] done = {false};
|
||||
|
||||
shown(() -> Core.app.post(() ->
|
||||
forEach(child -> {
|
||||
if(done[0]) return;
|
||||
|
||||
if(child instanceof ScrollPane){
|
||||
Core.scene.setScrollFocus(child);
|
||||
done[0] = true;
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
protected void onResize(Runnable run){
|
||||
Events.on(ResizeEvent.class, event -> {
|
||||
if(isShown()){
|
||||
run.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCloseButton(){
|
||||
buttons.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f, 64f);
|
||||
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
|
||||
Core.app.post(this::hide);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
96
core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java
Normal file
96
core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.Stats.RankResult;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Item.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class GameOverDialog extends FloatingDialog{
|
||||
private Team winner;
|
||||
|
||||
public GameOverDialog(){
|
||||
super("$gameover");
|
||||
setFillParent(true);
|
||||
shown(this::rebuild);
|
||||
}
|
||||
|
||||
public void show(Team winner){
|
||||
this.winner = winner;
|
||||
show();
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
title.setText(state.launched ? "$launch.title" : "$gameover");
|
||||
buttons.clear();
|
||||
cont.clear();
|
||||
|
||||
buttons.margin(10);
|
||||
|
||||
if(state.rules.pvp){
|
||||
cont.add(Core.bundle.format("gameover.pvp", winner.localized())).pad(6);
|
||||
buttons.addButton("$menu", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}else{
|
||||
if(control.isHighScore()){
|
||||
cont.add("$highscore").pad(6);
|
||||
cont.row();
|
||||
}
|
||||
|
||||
cont.pane(t -> {
|
||||
t.margin(13f);
|
||||
t.left().defaults().left();
|
||||
t.add(Core.bundle.format("stat.wave", state.stats.wavesLasted));
|
||||
t.row();
|
||||
t.add(Core.bundle.format("stat.enemiesDestroyed", state.stats.enemyUnitsDestroyed));
|
||||
t.row();
|
||||
t.add(Core.bundle.format("stat.built", state.stats.buildingsBuilt));
|
||||
t.row();
|
||||
t.add(Core.bundle.format("stat.destroyed", state.stats.buildingsDestroyed));
|
||||
t.row();
|
||||
t.add(Core.bundle.format("stat.deconstructed", state.stats.buildingsDeconstructed));
|
||||
t.row();
|
||||
if(world.isZone() && !state.stats.itemsDelivered.isEmpty()){
|
||||
t.add("$stat.delivered");
|
||||
t.row();
|
||||
for(Item item : content.items()){
|
||||
if(state.stats.itemsDelivered.get(item, 0) > 0){
|
||||
t.table(items -> {
|
||||
items.add(" [LIGHT_GRAY]" + state.stats.itemsDelivered.get(item, 0));
|
||||
items.addImage(item.icon(Icon.medium)).size(8 * 3).pad(4);
|
||||
}).left();
|
||||
t.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(world.isZone()){
|
||||
RankResult result = state.stats.calculateRank(world.getZone(), state.launched);
|
||||
t.add(Core.bundle.format("stat.rank", result.rank + result.modifier));
|
||||
t.row();
|
||||
}
|
||||
}).pad(12);
|
||||
|
||||
if(world.isZone()){
|
||||
buttons.addButton("$continue", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
ui.deploy.show();
|
||||
}).size(130f, 60f);
|
||||
}else{
|
||||
buttons.addButton("$menu", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -18,48 +17,52 @@ public class HostDialog extends FloatingDialog{
|
||||
float w = 300;
|
||||
|
||||
public HostDialog(){
|
||||
super("$text.hostserver");
|
||||
super("$hostserver");
|
||||
|
||||
addCloseButton();
|
||||
|
||||
content().table(t -> {
|
||||
t.add("$text.name").padRight(10);
|
||||
t.addField(Settings.getString("name"), text -> {
|
||||
if(text.isEmpty()) return;
|
||||
Vars.player.name = text;
|
||||
Settings.put("name", text);
|
||||
Settings.save();
|
||||
cont.table(t -> {
|
||||
t.add("$name").padRight(10);
|
||||
t.addField(Core.settings.getString("name"), text -> {
|
||||
player.name = text;
|
||||
Core.settings.put("name", text);
|
||||
Core.settings.save();
|
||||
ui.listfrag.rebuild();
|
||||
}).grow().pad(8).get().setMaxLength(40);
|
||||
|
||||
ImageButton button = t.addImageButton("white", 40, () -> {
|
||||
ImageButton button = t.addImageButton("white", "clear-full", 40, () -> {
|
||||
new ColorPickDialog().show(color -> {
|
||||
player.color.set(color);
|
||||
Settings.putInt("color", Color.rgba8888(color));
|
||||
Settings.save();
|
||||
Core.settings.put("color-0", Color.rgba8888(color));
|
||||
Core.settings.save();
|
||||
});
|
||||
}).size(50f, 54f).get();
|
||||
button.update(() -> button.getStyle().imageUpColor = player.getColor());
|
||||
}).size(54f).get();
|
||||
button.update(() -> button.getStyle().imageUpColor = player.color);
|
||||
}).width(w).height(70f).pad(4).colspan(3);
|
||||
|
||||
content().row();
|
||||
cont.row();
|
||||
|
||||
content().add().width(65f);
|
||||
cont.add().width(65f);
|
||||
|
||||
content().addButton("$text.host", () -> {
|
||||
ui.loadfrag.show("$text.hosting");
|
||||
Timers.runTask(5f, () -> {
|
||||
cont.addButton("$host", () -> {
|
||||
if(Core.settings.getString("name").trim().isEmpty()){
|
||||
ui.showInfo("$noname");
|
||||
return;
|
||||
}
|
||||
|
||||
ui.loadfrag.show("$hosting");
|
||||
Time.runTask(5f, () -> {
|
||||
try{
|
||||
Net.host(Vars.port);
|
||||
player.isAdmin = true;
|
||||
}catch (IOException e){
|
||||
ui.showError(Bundles.format("text.server.error", Strings.parseException(e, false)));
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true)));
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
hide();
|
||||
});
|
||||
}).width(w).height(70f);
|
||||
|
||||
content().addButton("?", () -> ui.showInfo("$text.host.info")).size(65f, 70f).padLeft(6f);
|
||||
cont.addButton("?", () -> ui.showInfo("$host.info")).size(65f, 70f).padLeft(6f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +1,103 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.annotations.Annotations.Serialize;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.scene.style.Drawable;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Cell;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.net.Host;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.style.Drawable;
|
||||
import io.anuke.ucore.scene.ui.Dialog;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Cell;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
|
||||
import static io.anuke.mindustry.Vars.player;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class JoinDialog extends FloatingDialog {
|
||||
public class JoinDialog extends FloatingDialog{
|
||||
Array<Server> servers = new Array<>();
|
||||
Dialog add;
|
||||
Server renaming;
|
||||
Table local = new Table();
|
||||
Table remote = new Table();
|
||||
Table hosts = new Table();
|
||||
float w = 500;
|
||||
int totalHosts;
|
||||
|
||||
public JoinDialog(){
|
||||
super("$text.joingame");
|
||||
super("$joingame");
|
||||
|
||||
loadServers();
|
||||
|
||||
buttons().add().width(60f);
|
||||
buttons().add().growX();
|
||||
buttons.add().width(60f);
|
||||
buttons.add().growX();
|
||||
|
||||
addCloseButton();
|
||||
|
||||
buttons().add().growX();
|
||||
buttons().addButton("?", () -> ui.showInfo("$text.join.info")).size(60f, 64f);
|
||||
buttons.add().growX();
|
||||
buttons.addButton("?", () -> ui.showInfo("$join.info")).size(60f, 64f);
|
||||
|
||||
add = new FloatingDialog("$text.joingame.title");
|
||||
add.content().add("$text.joingame.ip").padRight(5f).left();
|
||||
add = new FloatingDialog("$joingame.title");
|
||||
add.cont.add("$joingame.ip").padRight(5f).left();
|
||||
|
||||
Platform.instance.addDialog(add.content().addField(Settings.getString("ip"), text ->{
|
||||
Settings.putString("ip", text);
|
||||
Settings.save();
|
||||
}).size(320f, 54f).get(), 100);
|
||||
TextField field = add.cont.addField(Core.settings.getString("ip"), text -> {
|
||||
Core.settings.put("ip", text);
|
||||
Core.settings.save();
|
||||
}).size(320f, 54f).get();
|
||||
|
||||
add.content().row();
|
||||
add.buttons().defaults().size(140f, 60f).pad(4f);
|
||||
add.buttons().addButton("$text.cancel", add::hide);
|
||||
add.buttons().addButton("$text.ok", () -> {
|
||||
if(renaming == null) {
|
||||
Server server = new Server(Settings.getString("ip"), Strings.parseInt(Settings.getString("port")));
|
||||
Platform.instance.addDialog(field, 100);
|
||||
|
||||
add.cont.row();
|
||||
add.buttons.defaults().size(140f, 60f).pad(4f);
|
||||
add.buttons.addButton("$cancel", add::hide);
|
||||
add.buttons.addButton("$ok", () -> {
|
||||
if(renaming == null){
|
||||
Server server = new Server();
|
||||
server.setIP(Core.settings.getString("ip"));
|
||||
servers.add(server);
|
||||
saveServers();
|
||||
setupRemote();
|
||||
refreshRemote();
|
||||
}else{
|
||||
renaming.ip = Settings.getString("ip");
|
||||
renaming.setIP(Core.settings.getString("ip"));
|
||||
saveServers();
|
||||
setupRemote();
|
||||
refreshRemote();
|
||||
}
|
||||
add.hide();
|
||||
}).disabled(b -> Settings.getString("ip").isEmpty() || Net.active());
|
||||
}).disabled(b -> Core.settings.getString("ip").isEmpty() || Net.active());
|
||||
|
||||
add.shown(() -> {
|
||||
add.getTitleLabel().setText(renaming != null ? "$text.server.edit" : "$text.server.add");
|
||||
add.title.setText(renaming != null ? "$server.edit" : "$server.add");
|
||||
if(renaming != null){
|
||||
field.setText(renaming.displayIP());
|
||||
}
|
||||
});
|
||||
|
||||
setup();
|
||||
|
||||
shown(() -> {
|
||||
setup();
|
||||
refreshLocal();
|
||||
refreshRemote();
|
||||
});
|
||||
|
||||
onResize(this::setup);
|
||||
}
|
||||
|
||||
void setupRemote(){
|
||||
remote.clear();
|
||||
for (Server server : servers) {
|
||||
for(Server server : servers){
|
||||
//why are java lambdas this bad
|
||||
TextButton[] buttons = {null};
|
||||
|
||||
TextButton button = buttons[0] = remote.addButton("[accent]"+server.ip, "clear", () -> {
|
||||
if(!buttons[0].childrenPressed()) connect(server.ip, Vars.port);
|
||||
}).width(w).height(150f).pad(4f).get();
|
||||
TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> {
|
||||
if(!buttons[0].childrenPressed()){
|
||||
connect(server.ip, server.port);
|
||||
}
|
||||
}).width(targetWidth()).height(155f).pad(4f).get();
|
||||
|
||||
button.getLabel().setWrap(true);
|
||||
|
||||
@@ -103,17 +107,36 @@ public class JoinDialog extends FloatingDialog {
|
||||
|
||||
inner.add(button.getLabel()).growX();
|
||||
|
||||
inner.addImageButton("icon-loading", "empty", 16*2, () -> {
|
||||
inner.addImageButton("icon-arrow-up-small", "empty", iconsizesmall, () -> {
|
||||
int index = servers.indexOf(server);
|
||||
if(index > 0){
|
||||
servers.remove(index);
|
||||
servers.insert(0, server);
|
||||
|
||||
saveServers();
|
||||
setupRemote();
|
||||
for(Server other : servers){
|
||||
if(other.lastHost != null){
|
||||
setupServer(other, other.lastHost);
|
||||
}else{
|
||||
refreshServer(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}).margin(3f).padTop(6f).top().right();
|
||||
|
||||
inner.addImageButton("icon-loading-small", "empty", iconsizesmall, () -> {
|
||||
refreshServer(server);
|
||||
}).margin(3f).padTop(6f).top().right();
|
||||
|
||||
inner.addImageButton("icon-pencil", "empty", 16*2, () -> {
|
||||
inner.addImageButton("icon-pencil-small", "empty", iconsizesmall, () -> {
|
||||
renaming = server;
|
||||
add.show();
|
||||
}).margin(3f).padTop(6f).top().right();
|
||||
|
||||
inner.addImageButton("icon-trash-16", "empty", 16*2, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.server.delete", () -> {
|
||||
inner.addImageButton("icon-trash-16-small", "empty", iconsizesmall, () -> {
|
||||
ui.showConfirm("$confirm", "$server.delete", () -> {
|
||||
servers.removeValue(server, true);
|
||||
saveServers();
|
||||
setupRemote();
|
||||
@@ -123,7 +146,8 @@ public class JoinDialog extends FloatingDialog {
|
||||
|
||||
button.row();
|
||||
|
||||
server.content = button.table(t -> {}).grow().get();
|
||||
server.content = button.table(t -> {
|
||||
}).grow().get();
|
||||
|
||||
remote.row();
|
||||
}
|
||||
@@ -137,92 +161,84 @@ public class JoinDialog extends FloatingDialog {
|
||||
|
||||
void refreshServer(Server server){
|
||||
server.content.clear();
|
||||
server.content.label(() -> Bundles.get("text.server.refreshing") + Strings.animated(4, 11, "."));
|
||||
|
||||
Net.pingHost(server.ip, server.port, host -> {
|
||||
String versionString;
|
||||
|
||||
if(host.version == -1) {
|
||||
versionString = Bundles.format("text.server.version", Bundles.get("text.server.custombuild"));
|
||||
}else if(host.version == 0){
|
||||
versionString = Bundles.get("text.server.outdated");
|
||||
}else if(host.version < Version.build && Version.build != -1){
|
||||
versionString = Bundles.get("text.server.outdated") + "\n" +
|
||||
Bundles.format("text.server.version", host.version);
|
||||
}else if(host.version > Version.build && Version.build != -1){
|
||||
versionString = Bundles.get("text.server.outdated.client") + "\n" +
|
||||
Bundles.format("text.server.version", host.version);
|
||||
}else{
|
||||
versionString = Bundles.format("text.server.version", host.version);
|
||||
}
|
||||
server.content.label(() -> Core.bundle.get("server.refreshing") + Strings.animated(Time.time(), 4, 11, "."));
|
||||
|
||||
Net.pingHost(server.ip, server.port, host -> setupServer(server, host), e -> {
|
||||
server.content.clear();
|
||||
|
||||
server.content.table(t -> {
|
||||
t.add(versionString).left();
|
||||
t.row();
|
||||
t.add("[lightgray]" + Bundles.format("text.server.hostname", host.name)).left();
|
||||
t.row();
|
||||
t.add("[lightgray]" + (host.players != 1 ? Bundles.format("text.players", host.players) :
|
||||
Bundles.format("text.players.single", host.players))).left();
|
||||
t.row();
|
||||
t.add("[lightgray]" + Bundles.format("text.save.map", host.mapname) + " / " + Bundles.format("text.save.wave", host.wave)).left();
|
||||
}).expand().left().bottom().padLeft(12f).padBottom(8);
|
||||
|
||||
//server.content.add(versionString).top().expandY().top().expandX();
|
||||
|
||||
}, e -> {
|
||||
server.content.clear();
|
||||
server.content.add("$text.host.invalid");
|
||||
server.content.add("$host.invalid");
|
||||
});
|
||||
}
|
||||
|
||||
void refreshLocal(){
|
||||
if(!Vars.gwt) {
|
||||
local.clear();
|
||||
local.background("button");
|
||||
local.label(() -> "[accent]" + Bundles.get("text.hosts.discovering") + Strings.animated(4, 10f, ".")).pad(10f);
|
||||
Net.discoverServers(this::addLocalHosts);
|
||||
void setupServer(Server server, Host host){
|
||||
server.lastHost = host;
|
||||
String versionString;
|
||||
|
||||
if(host.version == -1){
|
||||
versionString = Core.bundle.format("server.version", Core.bundle.get("server.custombuild"), "");
|
||||
}else if(host.version == 0){
|
||||
versionString = Core.bundle.get("server.outdated");
|
||||
}else if(host.version < Version.build && Version.build != -1){
|
||||
versionString = Core.bundle.get("server.outdated") + "\n" +
|
||||
Core.bundle.format("server.version", host.version, "");
|
||||
}else if(host.version > Version.build && Version.build != -1){
|
||||
versionString = Core.bundle.get("server.outdated.client") + "\n" +
|
||||
Core.bundle.format("server.version", host.version, "");
|
||||
}else{
|
||||
versionString = Core.bundle.format("server.version", host.version, host.versionType);
|
||||
}
|
||||
|
||||
server.content.clear();
|
||||
|
||||
server.content.table(t -> {
|
||||
t.add("[lightgray]" + host.name).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||
t.row();
|
||||
t.add(versionString).left();
|
||||
t.row();
|
||||
t.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players) :
|
||||
Core.bundle.format("players.single", host.players))).left();
|
||||
t.row();
|
||||
t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[] / " + Core.bundle.format("save.wave", host.wave)).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||
}).expand().left().bottom().padLeft(12f).padBottom(8);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
float w = targetWidth();
|
||||
|
||||
hosts.clear();
|
||||
|
||||
hosts.add(remote).growX();
|
||||
hosts.row();
|
||||
hosts.add(local).width(w);
|
||||
|
||||
ScrollPane pane = new ScrollPane(hosts, "clear");
|
||||
ScrollPane pane = new ScrollPane(hosts);
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setScrollingDisabled(true, false);
|
||||
|
||||
setupRemote();
|
||||
refreshRemote();
|
||||
|
||||
content().clear();
|
||||
content().table(t -> {
|
||||
t.add("$text.name").padRight(10);
|
||||
t.addField(Settings.getString("name"), text -> {
|
||||
if(text.isEmpty()) return;
|
||||
Vars.player.name = text;
|
||||
Settings.put("name", text);
|
||||
Settings.save();
|
||||
}).grow().pad(8).get().setMaxLength(40);
|
||||
cont.clear();
|
||||
cont.table(t -> {
|
||||
t.add("$name").padRight(10);
|
||||
t.addField(Core.settings.getString("name"), text -> {
|
||||
player.name = text;
|
||||
Core.settings.put("name", text);
|
||||
Core.settings.save();
|
||||
}).grow().pad(8).get().setMaxLength(maxNameLength);
|
||||
|
||||
ImageButton button = t.addImageButton("white", 40, () -> {
|
||||
ImageButton button = t.addImageButton("white", "clear-full", 40, () -> {
|
||||
new ColorPickDialog().show(color -> {
|
||||
player.color.set(color);
|
||||
Settings.putInt("color", Color.rgba8888(color));
|
||||
Settings.save();
|
||||
Core.settings.put("color-0", Color.rgba8888(color));
|
||||
Core.settings.save();
|
||||
});
|
||||
}).size(50f, 54f).get();
|
||||
button.update(() -> button.getStyle().imageUpColor = player.getColor());
|
||||
}).size(54f).get();
|
||||
button.update(() -> button.getStyle().imageUpColor = player.color);
|
||||
}).width(w).height(70f).pad(4);
|
||||
content().row();
|
||||
content().add(pane).width(w + 34).pad(0);
|
||||
content().row();
|
||||
content().addCenteredImageTextButton("$text.server.add", "icon-add", "clear", 14*3, () -> {
|
||||
cont.row();
|
||||
cont.add(pane).width(w + 38).pad(0);
|
||||
cont.row();
|
||||
cont.addCenteredImageTextButton("$server.add", "icon-add", iconsize, () -> {
|
||||
renaming = null;
|
||||
add.show();
|
||||
}).marginLeft(6).width(w).height(80f).update(button -> {
|
||||
@@ -233,9 +249,9 @@ public class JoinDialog extends FloatingDialog {
|
||||
pad = 6;
|
||||
}
|
||||
|
||||
Cell<TextButton> cell = ((Table)pane.getParent()).getCell(button);
|
||||
Cell cell = ((Table)pane.getParent()).getCell(button);
|
||||
|
||||
if(!MathUtils.isEqual(cell.getMinWidth(), pw)){
|
||||
if(!Mathf.isEqual(cell.minWidth(), pw)){
|
||||
cell.width(pw);
|
||||
cell.padLeft(pad);
|
||||
pane.getParent().invalidateHierarchy();
|
||||
@@ -243,100 +259,113 @@ public class JoinDialog extends FloatingDialog {
|
||||
});
|
||||
}
|
||||
|
||||
void addLocalHosts(Array<Host> array){
|
||||
void refreshLocal(){
|
||||
totalHosts = 0;
|
||||
|
||||
local.clear();
|
||||
local.background((Drawable)null);
|
||||
local.table("button", t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX();
|
||||
Net.discoverServers(this::addLocalHost, this::finishLocalHosts);
|
||||
}
|
||||
|
||||
if(array.size == 0){
|
||||
local.add("$text.hosts.none").pad(10f);
|
||||
void finishLocalHosts(){
|
||||
if(totalHosts == 0){
|
||||
local.clear();
|
||||
local.background("button");
|
||||
local.add("$hosts.none").pad(10f);
|
||||
local.add().growX();
|
||||
local.addImageButton("icon-loading", 16*2f, this::refreshLocal).pad(-10f).padLeft(0).padTop(-6).size(70f, 74f);
|
||||
}else {
|
||||
for (Host a : array) {
|
||||
TextButton button = local.addButton("[accent]"+a.name, "clear", () -> {
|
||||
connect(a.address, Vars.port);
|
||||
}).width(w).height(80f).pad(4f).get();
|
||||
button.left();
|
||||
button.row();
|
||||
button.add("[lightgray]" + (a.players != 1 ? Bundles.format("text.players", a.players) :
|
||||
Bundles.format("text.players.single", a.players)));
|
||||
button.row();
|
||||
button.add("[lightgray]" + a.address).pad(4).left();
|
||||
|
||||
local.row();
|
||||
local.background((Drawable) null);
|
||||
}
|
||||
local.addImageButton("icon-loading", iconsize, this::refreshLocal).pad(-12f).padLeft(0).size(70f);
|
||||
}else{
|
||||
local.background((Drawable)null);
|
||||
}
|
||||
}
|
||||
|
||||
void addLocalHost(Host host){
|
||||
if(totalHosts == 0){
|
||||
local.clear();
|
||||
}
|
||||
local.background((Drawable)null);
|
||||
totalHosts++;
|
||||
float w = targetWidth();
|
||||
|
||||
local.row();
|
||||
|
||||
TextButton button = local.addButton("[accent]" + host.name, "clear", () -> connect(host.address, port))
|
||||
.width(w).height(80f).pad(4f).get();
|
||||
button.left();
|
||||
button.row();
|
||||
button.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players) :
|
||||
Core.bundle.format("players.single", host.players))).padBottom(5);
|
||||
}
|
||||
|
||||
void connect(String ip, int port){
|
||||
ui.loadfrag.show("$text.connecting");
|
||||
if(Core.settings.getString("name").trim().isEmpty()){
|
||||
ui.showInfo("$noname");
|
||||
return;
|
||||
}
|
||||
|
||||
Timers.runTask(2f, () -> {
|
||||
try{
|
||||
Vars.netClient.beginConnecting();
|
||||
Net.connect(ip, port);
|
||||
ui.loadfrag.show("$connecting");
|
||||
|
||||
ui.loadfrag.setButton(() -> {
|
||||
ui.loadfrag.hide();
|
||||
netClient.disconnectQuietly();
|
||||
});
|
||||
|
||||
Time.runTask(2f, () -> {
|
||||
logic.reset();
|
||||
Vars.netClient.beginConnecting();
|
||||
Net.connect(ip, port, () -> {
|
||||
hide();
|
||||
add.hide();
|
||||
}catch (Exception e) {
|
||||
Throwable t = e;
|
||||
while(t.getCause() != null){
|
||||
t = t.getCause();
|
||||
}
|
||||
//TODO localize
|
||||
String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase();
|
||||
if(error.contains("connection refused")) {
|
||||
error = "connection refused";
|
||||
}else if(error.contains("port out of range")){
|
||||
error = "invalid port!";
|
||||
}else if(error.contains("invalid argument")) {
|
||||
error = "invalid IP or port!";
|
||||
}else if(t.getClass().toString().toLowerCase().contains("sockettimeout")){
|
||||
error = "timed out!\nmake sure the host has port forwarding set up,\nand that the address is correct!";
|
||||
}else{
|
||||
error = Strings.parseException(e, false);
|
||||
}
|
||||
ui.showError(Bundles.format("text.connectfail", error));
|
||||
ui.loadfrag.hide();
|
||||
|
||||
Log.err(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void loadServers(){
|
||||
String h = Settings.getString("servers");
|
||||
String[] list = h.split("\\|\\|\\|");
|
||||
for(String fname : list){
|
||||
if(fname.isEmpty()) continue;
|
||||
String[] split = fname.split(":");
|
||||
String host = split[0];
|
||||
int port = Strings.parseInt(split[1]);
|
||||
float targetWidth(){
|
||||
return Core.graphics.isPortrait() ? 350f : 500f;
|
||||
}
|
||||
|
||||
if(port != Integer.MIN_VALUE) servers.add(new Server(host, port));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private void loadServers(){
|
||||
servers = Core.settings.getObject("server-list", Array.class, Array::new);
|
||||
}
|
||||
|
||||
private void saveServers(){
|
||||
StringBuilder out = new StringBuilder();
|
||||
for(Server server : servers){
|
||||
out.append(server.ip);
|
||||
out.append(":");
|
||||
out.append(server.port);
|
||||
out.append("|||");
|
||||
}
|
||||
Settings.putString("servers", out.toString());
|
||||
Settings.save();
|
||||
Core.settings.putObject("server-list", servers);
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
private class Server{
|
||||
@Serialize
|
||||
public static class Server{
|
||||
public String ip;
|
||||
public int port;
|
||||
public Host host;
|
||||
public Table content;
|
||||
|
||||
public Server(String ip, int port){
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
transient Table content;
|
||||
transient Host lastHost;
|
||||
|
||||
void setIP(String ip){
|
||||
|
||||
//parse ip:port, if unsuccessful, use default values
|
||||
if(ip.lastIndexOf(':') != -1 && ip.lastIndexOf(':') != ip.length() - 1){
|
||||
try{
|
||||
int idx = ip.lastIndexOf(':');
|
||||
this.ip = ip.substring(0, idx);
|
||||
this.port = Integer.parseInt(ip.substring(idx + 1));
|
||||
}catch(Exception e){
|
||||
this.ip = ip;
|
||||
this.port = Vars.port;
|
||||
}
|
||||
}else{
|
||||
this.ip = ip;
|
||||
this.port = Vars.port;
|
||||
}
|
||||
}
|
||||
|
||||
String displayIP(){
|
||||
return ip + (port != Vars.port ? ":" + port : "");
|
||||
}
|
||||
|
||||
public Server(){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Strings;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -14,9 +12,10 @@ import static io.anuke.mindustry.Vars.locales;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public class LanguageDialog extends FloatingDialog{
|
||||
private Locale lastLocale;
|
||||
|
||||
public LanguageDialog(){
|
||||
super("$text.settings.language");
|
||||
super("$settings.language");
|
||||
addCloseButton();
|
||||
setup();
|
||||
}
|
||||
@@ -24,26 +23,62 @@ public class LanguageDialog extends FloatingDialog{
|
||||
private void setup(){
|
||||
Table langs = new Table();
|
||||
langs.marginRight(24f).marginLeft(24f);
|
||||
ScrollPane pane = new ScrollPane(langs, "clear");
|
||||
ScrollPane pane = new ScrollPane(langs);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
|
||||
for(Locale loc : locales){
|
||||
TextButton button = new TextButton(Platform.instance.getLocaleName(loc), "toggle");
|
||||
button.setChecked(ui.getLocale().equals(loc));
|
||||
TextButton button = new TextButton(Strings.capitalize(loc.getDisplayName(loc)), "toggle");
|
||||
button.clicked(() -> {
|
||||
if(ui.getLocale().equals(loc)) return;
|
||||
Settings.putString("locale", loc.toString());
|
||||
Settings.save();
|
||||
if(getLocale().equals(loc)) return;
|
||||
Core.settings.put("locale", loc.toString());
|
||||
Core.settings.save();
|
||||
Log.info("Setting locale: {0}", loc.toString());
|
||||
ui.showInfo("$text.language.restart");
|
||||
ui.showInfo("$language.restart");
|
||||
});
|
||||
langs.add(button).group(group).update(t -> {
|
||||
t.setChecked(loc.equals(ui.getLocale()));
|
||||
}).size(400f, 60f).row();
|
||||
langs.add(button).group(group).update(t -> t.setChecked(loc.equals(getLocale()))).size(400f, 50f).pad(2).row();
|
||||
}
|
||||
|
||||
content().add(pane);
|
||||
cont.add(pane);
|
||||
}
|
||||
|
||||
public Locale getLocale(){
|
||||
String loc = Core.settings.getString("locale");
|
||||
|
||||
if(loc.equals("default")){
|
||||
findClosestLocale();
|
||||
}
|
||||
|
||||
if(lastLocale == null || !lastLocale.toString().equals(loc)){
|
||||
if(loc.contains("_")){
|
||||
String[] split = loc.split("_");
|
||||
lastLocale = new Locale(split[0], split[1]);
|
||||
}else{
|
||||
lastLocale = new Locale(loc);
|
||||
}
|
||||
}
|
||||
|
||||
return lastLocale;
|
||||
}
|
||||
|
||||
void findClosestLocale(){
|
||||
//check exact locale
|
||||
for(Locale l : locales){
|
||||
if(l.equals(Locale.getDefault())){
|
||||
Core.settings.put("locale", l.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//find by language
|
||||
for(Locale l : locales){
|
||||
if(l.getLanguage().equals(Locale.getDefault().getLanguage())){
|
||||
Core.settings.put("locale", l.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Core.settings.put("locale", new Locale("en").toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.mindustry.game.Difficulty;
|
||||
import io.anuke.mindustry.game.GameMode;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.event.ClickListener;
|
||||
import io.anuke.ucore.scene.event.InputEvent;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.*;
|
||||
import io.anuke.ucore.scene.ui.layout.Stack;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.utils.Elements;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class LevelDialog extends FloatingDialog{
|
||||
private Map selectedMap = world.maps().getMap(0);
|
||||
private ScrollPane pane;
|
||||
|
||||
public LevelDialog(){
|
||||
super("$text.level.select");
|
||||
getTitleTable().getCell(title()).growX().center();
|
||||
getTitleTable().center();
|
||||
addCloseButton();
|
||||
setup();
|
||||
}
|
||||
|
||||
public void reload(){
|
||||
content().clear();
|
||||
setup();
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Table maps = new Table();
|
||||
pane = new ScrollPane(maps);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
int maxwidth = 4;
|
||||
|
||||
Table selmode = new Table();
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
selmode.add("$text.level.mode").padRight(15f);
|
||||
|
||||
for(GameMode mode : GameMode.values()){
|
||||
TextButton[] b = {null};
|
||||
b[0] = Elements.newButton("$mode." + mode.name() + ".name", "toggle", () -> state.mode = mode);
|
||||
b[0].update(() -> b[0].setChecked(state.mode == mode));
|
||||
b[0].getLabelCell().wrap().growX().get().setAlignment(Align.center, Align.left);
|
||||
group.add(b[0]);
|
||||
selmode.add(b[0]).size(130f, 54f);
|
||||
}
|
||||
selmode.addButton("?", this::displayGameModeHelp).size(50f, 54f).padLeft(18f);
|
||||
|
||||
content().add(selmode);
|
||||
content().row();
|
||||
|
||||
Difficulty[] ds = Difficulty.values();
|
||||
|
||||
float s = 50f;
|
||||
|
||||
Table sdif = new Table();
|
||||
|
||||
sdif.add("$setting.difficulty.name").padRight(15f);
|
||||
|
||||
sdif.defaults().height(s+4);
|
||||
sdif.addImageButton("icon-arrow-left", 10*3, () -> {
|
||||
state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() - 1, ds.length)]);
|
||||
}).width(s);
|
||||
|
||||
sdif.addButton("", () -> {
|
||||
|
||||
}).update(t -> {
|
||||
t.setText(state.difficulty.toString());
|
||||
t.setTouchable(Touchable.disabled);
|
||||
}).width(180f);
|
||||
|
||||
sdif.addImageButton("icon-arrow-right", 10*3, () -> {
|
||||
state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() + 1, ds.length)]);
|
||||
}).width(s);
|
||||
|
||||
content().add(sdif);
|
||||
content().row();
|
||||
|
||||
int i = 0;
|
||||
for(Map map : world.maps().list()){
|
||||
|
||||
if(!map.visible && !debug) continue;
|
||||
|
||||
if(i % maxwidth == 0){
|
||||
maps.row();
|
||||
}
|
||||
|
||||
Table inset = new Table("pane-button");
|
||||
inset.add("[accent]" + Bundles.get("map."+map.name+".name", map.name)).pad(3f);
|
||||
inset.row();
|
||||
inset.label((() -> Bundles.format("text.level.highscore", Settings.getInt("hiscore" + map.name, 0)))).pad(3f).padLeft(-2).padRight(-2)
|
||||
.wrap().growX().get().setAlignment(Align.center, Align.left);
|
||||
inset.pack();
|
||||
|
||||
float images = 154f;
|
||||
|
||||
Stack stack = new Stack();
|
||||
|
||||
Image back = new Image("white");
|
||||
back.setColor(map.backgroundColor);
|
||||
|
||||
ImageButton image = new ImageButton(new TextureRegion(map.texture), "togglemap");
|
||||
image.row();
|
||||
image.add(inset).width(images+6);
|
||||
TextButton[] delete = new TextButton[1];
|
||||
if(map.custom){
|
||||
image.row();
|
||||
delete[0] = image.addButton("Delete", () -> {
|
||||
Timers.run(1f, () -> {
|
||||
ui.showConfirm("$text.level.delete.title", Bundles.format("text.level.delete", Bundles.get("map."+map.name+".name", map.name)), () -> {
|
||||
world.maps().removeMap(map);
|
||||
reload();
|
||||
Core.scene.setScrollFocus(pane);
|
||||
});
|
||||
});
|
||||
}).width(images+16).padBottom(-10f).grow().get();
|
||||
}
|
||||
|
||||
Vector2 hit = new Vector2();
|
||||
|
||||
image.addListener(new ClickListener(){
|
||||
public void clicked(InputEvent event, float x, float y){
|
||||
image.localToStageCoordinates(hit.set(x, y));
|
||||
if(delete[0] != null && (delete[0].getClickListener().isOver() || delete[0].getClickListener().isPressed()
|
||||
|| (Core.scene.hit(hit.x, hit.y, true) != null &&
|
||||
Core.scene.hit(hit.x, hit.y, true).isDescendantOf(delete[0])))){
|
||||
return;
|
||||
}
|
||||
|
||||
selectedMap = map;
|
||||
hide();
|
||||
control.playMap(selectedMap);
|
||||
}
|
||||
});
|
||||
image.getImageCell().size(images);
|
||||
|
||||
stack.add(back);
|
||||
stack.add(image);
|
||||
|
||||
maps.add(stack).width(170).top().pad(4f);
|
||||
|
||||
maps.marginRight(26);
|
||||
|
||||
i ++;
|
||||
}
|
||||
|
||||
content().add(pane).uniformX();
|
||||
|
||||
shown(()->{
|
||||
//this is necessary for some reason?
|
||||
Timers.run(2f, ()->{
|
||||
Core.scene.setScrollFocus(pane);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void displayGameModeHelp() {
|
||||
FloatingDialog d = new FloatingDialog(Bundles.get("mode.text.help.title"));
|
||||
d.setFillParent(false);
|
||||
Table table = new Table();
|
||||
table.defaults().pad(1f);
|
||||
ScrollPane pane = new ScrollPane(table, "clear");
|
||||
pane.setFadeScrollBars(false);
|
||||
table.row();
|
||||
for(GameMode mode : GameMode.values()){
|
||||
table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(600f);
|
||||
table.row();
|
||||
}
|
||||
|
||||
d.content().add(pane);
|
||||
d.buttons().addButton("$text.ok", d::hide).size(110, 50).pad(10f);
|
||||
d.show();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,195 +1,192 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.game.Saves.SaveSlot;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.io.Saves.SaveSlot;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
import io.anuke.mindustry.io.SaveIO.SaveException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class LoadDialog extends FloatingDialog{
|
||||
ScrollPane pane;
|
||||
Table slots;
|
||||
ScrollPane pane;
|
||||
Table slots;
|
||||
|
||||
public LoadDialog() {
|
||||
this("$text.loadgame");
|
||||
}
|
||||
public LoadDialog(){
|
||||
this("$loadgame");
|
||||
}
|
||||
|
||||
public LoadDialog(String title) {
|
||||
super(title);
|
||||
setup();
|
||||
public LoadDialog(String title){
|
||||
super(title);
|
||||
setup();
|
||||
|
||||
shown(() -> {
|
||||
setup();
|
||||
Timers.runTask(2f, () -> Core.scene.setScrollFocus(pane));
|
||||
});
|
||||
shown(() -> {
|
||||
setup();
|
||||
Time.runTask(2f, () -> Core.scene.setScrollFocus(pane));
|
||||
});
|
||||
|
||||
addCloseButton();
|
||||
}
|
||||
addCloseButton();
|
||||
}
|
||||
|
||||
protected void setup(){
|
||||
content().clear();
|
||||
protected void setup(){
|
||||
cont.clear();
|
||||
|
||||
slots = new Table();
|
||||
pane = new ScrollPane(slots, "clear-black");
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setScrollingDisabled(true, false);
|
||||
slots = new Table();
|
||||
pane = new ScrollPane(slots);
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setScrollingDisabled(true, false);
|
||||
|
||||
slots.marginRight(24);
|
||||
slots.marginRight(24);
|
||||
|
||||
Timers.runTask(2f, () -> Core.scene.setScrollFocus(pane));
|
||||
Time.runTask(2f, () -> Core.scene.setScrollFocus(pane));
|
||||
|
||||
Array<SaveSlot> array = control.getSaves().getSaveSlots();
|
||||
Array<SaveSlot> array = control.saves.getSaveSlots();
|
||||
|
||||
for(SaveSlot slot : array){
|
||||
for(SaveSlot slot : array){
|
||||
if(slot.isHidden()) continue;
|
||||
|
||||
TextButton button = new TextButton("[accent]" + slot.getName(), "clear");
|
||||
button.getLabelCell().growX().left();
|
||||
button.getLabelCell().padBottom(8f);
|
||||
button.getLabelCell().top().left().growX();
|
||||
TextButton button = new TextButton("[accent]" + slot.getName(), "clear");
|
||||
button.getLabelCell().growX().left();
|
||||
button.getLabelCell().padBottom(8f);
|
||||
button.getLabelCell().top().left().growX();
|
||||
|
||||
button.defaults().left();
|
||||
button.defaults().left();
|
||||
|
||||
button.table(t -> {
|
||||
t.right();
|
||||
button.table(t -> {
|
||||
t.right();
|
||||
|
||||
t.addImageButton("icon-floppy", "emptytoggle", 14*3, () -> {
|
||||
slot.setAutosave(!slot.isAutosave());
|
||||
}).checked(slot.isAutosave()).right();
|
||||
t.addImageButton("icon-floppy", "emptytoggle", iconsize, () -> {
|
||||
slot.setAutosave(!slot.isAutosave());
|
||||
}).checked(slot.isAutosave()).right();
|
||||
|
||||
t.addImageButton("icon-trash", "empty", 14*3, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.save.delete.confirm", () -> {
|
||||
slot.delete();
|
||||
setup();
|
||||
});
|
||||
}).size(14*3).right();
|
||||
t.addImageButton("icon-trash", "empty", iconsize, () -> {
|
||||
ui.showConfirm("$confirm", "$save.delete.confirm", () -> {
|
||||
slot.delete();
|
||||
setup();
|
||||
});
|
||||
}).size(iconsize).right();
|
||||
|
||||
t.addImageButton("icon-pencil-small", "empty", 14*3, () -> {
|
||||
ui.showTextInput("$text.save.rename", "$text.save.rename.text", slot.getName(), text -> {
|
||||
slot.setName(text);
|
||||
setup();
|
||||
});
|
||||
}).size(14*3).right();
|
||||
t.addImageButton("icon-pencil", "empty", iconsize, () -> {
|
||||
ui.showTextInput("$save.rename", "$save.rename.text", slot.getName(), text -> {
|
||||
slot.setName(text);
|
||||
setup();
|
||||
});
|
||||
}).size(iconsize).right();
|
||||
|
||||
if(!gwt) {
|
||||
t.addImageButton("icon-save", "empty", 14 * 3, () -> {
|
||||
if(!ios) {
|
||||
Platform.instance.showFileChooser(Bundles.get("text.save.export"), "Mindustry Save", file -> {
|
||||
try {
|
||||
slot.exportFile(file);
|
||||
setup();
|
||||
} catch (IOException e) {
|
||||
ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false)));
|
||||
}
|
||||
}, false, "mins");
|
||||
}else{
|
||||
try {
|
||||
FileHandle file = Gdx.files.local("save-" + slot.getName() + ".mins");
|
||||
t.addImageButton("icon-save", "empty", iconsize, () -> {
|
||||
if(!ios){
|
||||
Platform.instance.showFileChooser(Core.bundle.get("save.export"), "Mindustry Save", file -> {
|
||||
try{
|
||||
slot.exportFile(file);
|
||||
Platform.instance.shareFile(file);
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false)));
|
||||
setup();
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, true)));
|
||||
}
|
||||
}, false, FileChooser.saveFiles);
|
||||
}else{
|
||||
try{
|
||||
FileHandle file = Core.files.local("save-" + slot.getName() + "." + Vars.saveExtension);
|
||||
slot.exportFile(file);
|
||||
Platform.instance.shareFile(file);
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, true)));
|
||||
}
|
||||
}).size(14 * 3).right();
|
||||
}
|
||||
}
|
||||
}).size(iconsize).right();
|
||||
|
||||
}).padRight(-10).growX();
|
||||
|
||||
String color = "[lightgray]";
|
||||
}).padRight(-10).growX();
|
||||
|
||||
button.defaults().padBottom(3);
|
||||
button.row();
|
||||
button.add(Bundles.format("text.save.map", color+slot.getMap().localized()));
|
||||
button.row();
|
||||
button.add(Bundles.get("text.level.mode") + " " +color+ slot.getMode());
|
||||
button.row();
|
||||
button.add(Bundles.format("text.save.wave", color+slot.getWave()));
|
||||
button.row();
|
||||
button.add(Bundles.format("text.save.difficulty", color+slot.getDifficulty()));
|
||||
button.row();
|
||||
button.label(() -> Bundles.format("text.save.autosave", color + Bundles.get(slot.isAutosave() ? "text.on" : "text.off")));
|
||||
button.row();
|
||||
button.add();
|
||||
button.add(Bundles.format("text.save.date", color+slot.getDate()));
|
||||
button.row();
|
||||
modifyButton(button, slot);
|
||||
String color = "[lightgray]";
|
||||
|
||||
slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).marginLeft(20f).marginRight(20f);
|
||||
slots.row();
|
||||
}
|
||||
button.defaults().padBottom(3);
|
||||
button.row();
|
||||
button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name())));
|
||||
button.row();
|
||||
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
|
||||
button.row();
|
||||
button.label(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
|
||||
button.row();
|
||||
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
|
||||
button.row();
|
||||
button.add(Core.bundle.format("save.date", color + slot.getDate())).colspan(2).padTop(5).right();
|
||||
button.row();
|
||||
modifyButton(button, slot);
|
||||
|
||||
content().add(pane);
|
||||
slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).marginLeft(20f).marginRight(20f);
|
||||
slots.row();
|
||||
}
|
||||
|
||||
addSetup();
|
||||
}
|
||||
cont.add(pane);
|
||||
|
||||
public void addSetup(){
|
||||
if(control.getSaves().getSaveSlots().size == 0) {
|
||||
addSetup();
|
||||
}
|
||||
|
||||
slots.row();
|
||||
slots.addButton("$text.save.none", "clear", () -> {
|
||||
}).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f);
|
||||
}
|
||||
public void addSetup(){
|
||||
boolean valids = false;
|
||||
for(SaveSlot slot : control.saves.getSaveSlots()) if(!slot.isHidden()) valids = true;
|
||||
|
||||
slots.row();
|
||||
if(!valids){
|
||||
|
||||
if(gwt || ios) return;
|
||||
slots.row();
|
||||
slots.addButton("$save.none", () -> {
|
||||
}).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f);
|
||||
}
|
||||
|
||||
slots.addImageTextButton("$text.save.import", "icon-add", "clear", 14*3, () -> {
|
||||
Platform.instance.showFileChooser(Bundles.get("text.save.import"), "Mindustry Save", file -> {
|
||||
if(SaveIO.isSaveValid(file)){
|
||||
try{
|
||||
control.getSaves().importSave(file);
|
||||
setup();
|
||||
}catch (IOException e){
|
||||
ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false)));
|
||||
}
|
||||
}else{
|
||||
ui.showError("$text.save.import.invalid");
|
||||
}
|
||||
}, true, "mins");
|
||||
}).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);
|
||||
}
|
||||
slots.row();
|
||||
|
||||
public void runLoadSave(SaveSlot slot){
|
||||
ui.loadfrag.show();
|
||||
if(ios) return;
|
||||
|
||||
Timers.runTask(3f, () -> {
|
||||
ui.loadfrag.hide();
|
||||
hide();
|
||||
slots.addImageTextButton("$save.import", "icon-add", iconsize, () -> {
|
||||
Platform.instance.showFileChooser(Core.bundle.get("save.import"), "Mindustry Save", file -> {
|
||||
if(SaveIO.isSaveValid(file)){
|
||||
try{
|
||||
control.saves.importSave(file);
|
||||
setup();
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
ui.showError(Core.bundle.format("save.import.fail", Strings.parseException(e, true)));
|
||||
}
|
||||
}else{
|
||||
ui.showError("$save.import.invalid");
|
||||
}
|
||||
}, true, FileChooser.saveFiles);
|
||||
}).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);
|
||||
}
|
||||
|
||||
public void runLoadSave(SaveSlot slot){
|
||||
hide();
|
||||
ui.paused.hide();
|
||||
|
||||
ui.loadAnd(() -> {
|
||||
try{
|
||||
slot.load();
|
||||
state.set(State.playing);
|
||||
ui.paused.hide();
|
||||
}catch(Exception e){
|
||||
}catch(SaveException e){
|
||||
Log.err(e);
|
||||
ui.paused.hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
ui.showError("$text.save.corrupted");
|
||||
ui.showError("$save.corrupted");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void modifyButton(TextButton button, SaveSlot slot){
|
||||
button.clicked(() -> {
|
||||
if(!button.childrenPressed()){
|
||||
runLoadSave(slot);
|
||||
}
|
||||
});
|
||||
}
|
||||
public void modifyButton(TextButton button, SaveSlot slot){
|
||||
button.clicked(() -> {
|
||||
if(!button.childrenPressed()){
|
||||
int build = slot.getBuild();
|
||||
runLoadSave(slot);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
94
core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java
Normal file
94
core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Scaling;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MapPlayDialog extends FloatingDialog{
|
||||
CustomRulesDialog dialog = new CustomRulesDialog();
|
||||
Rules rules;
|
||||
Gamemode selectedGamemode = Gamemode.survival;
|
||||
|
||||
public MapPlayDialog(){
|
||||
super("");
|
||||
setFillParent(false);
|
||||
}
|
||||
|
||||
public void show(Map map){
|
||||
title.setText(map.name());
|
||||
cont.clearChildren();
|
||||
|
||||
//reset to a valid mode after switching to attack
|
||||
if((selectedGamemode == Gamemode.attack && !map.hasEnemyCore()) || (selectedGamemode == Gamemode.pvp && !map.hasOtherCores())){
|
||||
selectedGamemode = Gamemode.survival;
|
||||
}
|
||||
|
||||
rules = map.rules();
|
||||
rules = selectedGamemode.apply(map.rules());
|
||||
|
||||
Table selmode = new Table();
|
||||
selmode.add("$level.mode").colspan(4);
|
||||
selmode.row();
|
||||
int i = 0;
|
||||
|
||||
Table modes = new Table();
|
||||
|
||||
for(Gamemode mode : Gamemode.values()){
|
||||
if(mode.hidden) continue;
|
||||
|
||||
if((mode == Gamemode.attack && !map.hasEnemyCore()) || (mode == Gamemode.pvp && !map.hasOtherCores())){
|
||||
continue;
|
||||
}
|
||||
|
||||
modes.addButton(mode.toString(), "toggle", () -> {
|
||||
selectedGamemode = mode;
|
||||
rules = mode.apply(map.rules());
|
||||
}).update(b -> b.setChecked(selectedGamemode == mode)).size(140f, 54f);
|
||||
if(i++ % 2 == 1) modes.row();
|
||||
}
|
||||
selmode.add(modes);
|
||||
selmode.addButton("?", this::displayGameModeHelp).width(50f).fillY().padLeft(18f);
|
||||
|
||||
cont.add(selmode);
|
||||
cont.row();
|
||||
cont.addImageTextButton("$customize", "icon-tools-small", iconsizesmall, () -> dialog.show(rules, () -> rules = (selectedGamemode == null ? map.rules() : selectedGamemode.apply(map.rules())))).width(230);
|
||||
cont.row();
|
||||
cont.add(new BorderImage(map.texture, 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit);
|
||||
|
||||
buttons.clearChildren();
|
||||
addCloseButton();
|
||||
|
||||
buttons.addImageTextButton("$play", "icon-play", 8*3, () -> {
|
||||
control.playMap(map, rules);
|
||||
hide();
|
||||
ui.custom.hide();
|
||||
}).size(210f, 64f);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
private void displayGameModeHelp(){
|
||||
FloatingDialog d = new FloatingDialog(Core.bundle.get("mode.help.title"));
|
||||
d.setFillParent(false);
|
||||
Table table = new Table();
|
||||
table.defaults().pad(1f);
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
pane.setFadeScrollBars(false);
|
||||
table.row();
|
||||
for(Gamemode mode : Gamemode.values()){
|
||||
if(mode.hidden) continue;
|
||||
table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(400f);
|
||||
table.row();
|
||||
}
|
||||
|
||||
d.cont.add(pane);
|
||||
d.buttons.addButton("$ok", d::hide).size(110, 50).pad(10f);
|
||||
d.show();
|
||||
}
|
||||
}
|
||||
169
core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java
Normal file
169
core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Scaling;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MapsDialog extends FloatingDialog{
|
||||
private FloatingDialog dialog;
|
||||
|
||||
public MapsDialog(){
|
||||
super("$maps");
|
||||
|
||||
addCloseButton();
|
||||
buttons.addImageTextButton("$editor.importmap", "icon-add", iconsize, () -> {
|
||||
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
|
||||
world.maps.tryCatchMapError(() -> {
|
||||
if(MapIO.isImage(file)){
|
||||
ui.showError("$editor.errorimage");
|
||||
return;
|
||||
}
|
||||
|
||||
Map map;
|
||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||
map = MapIO.createMap(file, true);
|
||||
}else{
|
||||
map = world.maps.makeLegacyMap(file);
|
||||
}
|
||||
|
||||
String name = map.tags.get("name");
|
||||
if(name == null){
|
||||
ui.showError("$editor.errorname");
|
||||
return;
|
||||
}
|
||||
|
||||
Map conflict = world.maps.all().find(m -> m.name().equals(name));
|
||||
|
||||
if(conflict != null && !conflict.custom){
|
||||
ui.showInfo(Core.bundle.format("editor.import.exists", name));
|
||||
}else if(conflict != null){
|
||||
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
||||
world.maps.tryCatchMapError(() -> {
|
||||
world.maps.importMap(file);
|
||||
setup();
|
||||
});
|
||||
});
|
||||
}else{
|
||||
world.maps.importMap(map.file);
|
||||
setup();
|
||||
}
|
||||
|
||||
});
|
||||
}, true, FileChooser.anyMapFiles);
|
||||
}).size(230f, 64f);
|
||||
|
||||
shown(this::setup);
|
||||
onResize(() -> {
|
||||
if(dialog != null){
|
||||
dialog.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
|
||||
Table maps = new Table();
|
||||
maps.marginRight(24);
|
||||
|
||||
ScrollPane pane = new ScrollPane(maps);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
int maxwidth = Core.graphics.isPortrait() ? 2 : 4;
|
||||
float mapsize = 200f;
|
||||
|
||||
int i = 0;
|
||||
for(Map map : world.maps.all()){
|
||||
|
||||
if(i % maxwidth == 0){
|
||||
maps.row();
|
||||
}
|
||||
|
||||
TextButton button = maps.addButton("", "clear", () -> showMapInfo(map)).width(mapsize).pad(8).get();
|
||||
button.clearChildren();
|
||||
button.margin(9);
|
||||
button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true);
|
||||
button.row();
|
||||
button.addImage("white").growX().pad(4).color(Color.GRAY);
|
||||
button.row();
|
||||
button.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize - 20f);
|
||||
button.row();
|
||||
button.add(map.custom ? "$custom" : "$builtin").color(Color.GRAY).padTop(3);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if(world.maps.all().size == 0){
|
||||
maps.add("$maps.none");
|
||||
}
|
||||
|
||||
cont.add(pane).uniformX();
|
||||
}
|
||||
|
||||
void showMapInfo(Map map){
|
||||
dialog = new FloatingDialog("$editor.mapinfo");
|
||||
dialog.addCloseButton();
|
||||
|
||||
float mapsize = Core.graphics.isPortrait() ? 160f : 300f;
|
||||
Table table = dialog.cont;
|
||||
|
||||
table.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize);
|
||||
|
||||
table.table("flat", desc -> {
|
||||
desc.top();
|
||||
Table t = new Table();
|
||||
t.margin(6);
|
||||
|
||||
ScrollPane pane = new ScrollPane(t);
|
||||
desc.add(pane).grow();
|
||||
|
||||
t.top();
|
||||
t.defaults().padTop(10).left();
|
||||
|
||||
t.add("$editor.name").padRight(10).color(Color.GRAY).padTop(0);
|
||||
t.row();
|
||||
t.add(map.name()).growX().wrap().padTop(2);
|
||||
t.row();
|
||||
t.add("$editor.author").padRight(10).color(Color.GRAY);
|
||||
t.row();
|
||||
t.add(map.author()).growX().wrap().padTop(2);
|
||||
t.row();
|
||||
t.add("$editor.description").padRight(10).color(Color.GRAY).top();
|
||||
t.row();
|
||||
t.add(map.description()).growX().wrap().padTop(2);
|
||||
}).height(mapsize).width(mapsize);
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImageTextButton("$editor.openin", "icon-load-map", iconsize, () -> {
|
||||
try{
|
||||
Vars.ui.editor.beginEditMap(map.file);
|
||||
dialog.hide();
|
||||
hide();
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
ui.showError("$error.mapnotfound");
|
||||
}
|
||||
}).fillX().height(54f).marginLeft(10);
|
||||
|
||||
table.addImageTextButton("$delete", "icon-trash-16", iconsize, () -> {
|
||||
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> {
|
||||
world.maps.removeMap(map);
|
||||
dialog.hide();
|
||||
setup();
|
||||
});
|
||||
}).fillX().height(54f).marginLeft(10).disabled(!map.custom).touchable(map.custom ? Touchable.enabled : Touchable.disabled);
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
64
core/src/io/anuke/mindustry/ui/dialogs/MinimapDialog.java
Normal file
64
core/src/io/anuke/mindustry/ui/dialogs/MinimapDialog.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.event.InputEvent;
|
||||
import io.anuke.arc.scene.event.InputListener;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MinimapDialog extends FloatingDialog{
|
||||
|
||||
public MinimapDialog(){
|
||||
super("$minimap");
|
||||
setFillParent(false);
|
||||
|
||||
shown(this::setup);
|
||||
|
||||
addCloseButton();
|
||||
shouldPause = true;
|
||||
}
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
float size = Math.min(Core.graphics.getWidth(), Core.graphics.getHeight()) / Unit.dp.scl(1f) / 1.3f;
|
||||
|
||||
cont.table("pane", t -> {
|
||||
t.addRect((x, y, width, height) -> {
|
||||
if(renderer.minimap.getRegion() == null) return;
|
||||
Draw.color(Color.WHITE);
|
||||
Draw.rect(renderer.minimap.getRegion(), x + width / 2f, y + height / 2f, width, height);
|
||||
|
||||
if(renderer.minimap.getTexture() != null){
|
||||
renderer.minimap.drawEntities(x, y, width, height);
|
||||
}
|
||||
}).grow();
|
||||
}).size(size);
|
||||
|
||||
cont.addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean scrolled(InputEvent event, float x, float y, float amountx, float amounty){
|
||||
renderer.minimap.zoomBy(amounty);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchDragged(InputEvent event, float x, float y, int pointer){
|
||||
if(mobile){
|
||||
float max = Math.min(world.width(), world.height()) / 16f / 2f;
|
||||
renderer.minimap.setZoom(1f + y / cont.getHeight() * (max - 1f));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Core.app.post(() -> Core.scene.setScrollFocus(cont));
|
||||
}
|
||||
}
|
||||
@@ -1,149 +1,122 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.ui.PressGroup;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.builders.build;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class PausedDialog extends FloatingDialog{
|
||||
private SaveDialog save = new SaveDialog();
|
||||
private LoadDialog load = new LoadDialog();
|
||||
public boolean wasPaused = false;
|
||||
private SaveDialog save = new SaveDialog();
|
||||
private LoadDialog load = new LoadDialog();
|
||||
private boolean wasClient = false;
|
||||
|
||||
public PausedDialog() {
|
||||
super("$text.menu");
|
||||
setup();
|
||||
}
|
||||
public PausedDialog(){
|
||||
super("$menu");
|
||||
shouldPause = true;
|
||||
|
||||
void setup(){
|
||||
update(() -> {
|
||||
if(state.is(State.menu) && isShown()){
|
||||
hide();
|
||||
}
|
||||
});
|
||||
shown(this::rebuild);
|
||||
|
||||
shown(() -> {
|
||||
wasPaused = state.is(State.paused);
|
||||
if(!Net.active()) state.set(State.paused);
|
||||
});
|
||||
|
||||
if(!mobile){
|
||||
content().defaults().width(220).height(50);
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
|
||||
hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
content().addButton("$text.back", () -> {
|
||||
hide();
|
||||
if((!wasPaused || Net.active()) && !state.is(State.menu))
|
||||
state.set(State.playing);
|
||||
});
|
||||
void rebuild(){
|
||||
cont.clear();
|
||||
|
||||
content().row();
|
||||
content().addButton("$text.settings", ui.settings::show);
|
||||
update(() -> {
|
||||
if(state.is(State.menu) && isShown()){
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
content().row();
|
||||
content().addButton("$text.savegame", () -> {
|
||||
save.show();
|
||||
}).disabled(b -> world.getMap().id == -1);
|
||||
if(!mobile){
|
||||
float dw = 210f;
|
||||
cont.defaults().width(dw).height(50).pad(5f);
|
||||
|
||||
content().row();
|
||||
content().addButton("$text.loadgame", () -> {
|
||||
load.show();
|
||||
}).disabled(b -> Net.active());
|
||||
cont.addButton("$back", this::hide).colspan(2).width(dw * 2 + 20f);
|
||||
|
||||
content().row();
|
||||
cont.row();
|
||||
if(world.isZone()){
|
||||
cont.addButton("$techtree", ui.tech::show);
|
||||
}else{
|
||||
cont.addButton("$database", ui.database::show);
|
||||
}
|
||||
cont.addButton("$settings", ui.settings::show);
|
||||
|
||||
if(!gwt) {
|
||||
content().addButton("$text.hostserver", () -> {
|
||||
ui.host.show();
|
||||
}).disabled(b -> Net.active());
|
||||
}
|
||||
if(!world.isZone() && !state.isEditor()){
|
||||
cont.row();
|
||||
cont.addButton("$savegame", save::show);
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> Net.active());
|
||||
}
|
||||
|
||||
content().row();
|
||||
cont.row();
|
||||
|
||||
content().addButton("$text.quit", () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.quit.confirm", () -> {
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
});
|
||||
cont.addButton("$hostserver", ui.host::show).disabled(b -> Net.active()).colspan(2).width(dw * 2 + 20f);
|
||||
cont.row();
|
||||
|
||||
}else{
|
||||
build.begin(content());
|
||||
|
||||
PressGroup group = new PressGroup();
|
||||
|
||||
content().defaults().size(120f).pad(5);
|
||||
float isize = 14f*4;
|
||||
|
||||
new imagebutton("icon-play-2", isize, () -> {
|
||||
hide();
|
||||
if(!wasPaused && !state.is(State.menu))
|
||||
state.set(State.playing);
|
||||
}).text("$text.back").padTop(4f);
|
||||
|
||||
new imagebutton("icon-tools", isize, ui.settings::show).text("$text.settings").padTop(4f);
|
||||
|
||||
imagebutton sa = new imagebutton("icon-save", isize, save::show);
|
||||
sa.text("$text.save").padTop(4f);
|
||||
sa.cell.disabled(b -> world.getMap().id == -1);
|
||||
cont.addButton("$quit", () -> {
|
||||
ui.showConfirm("$confirm", "$quit.confirm", () -> {
|
||||
wasClient = Net.client();
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
}).colspan(2).width(dw + 10f);
|
||||
|
||||
content().row();
|
||||
|
||||
imagebutton lo = new imagebutton("icon-load", isize, load::show);
|
||||
lo.text("$text.load").padTop(4f);
|
||||
lo.cell.disabled(b -> Net.active());
|
||||
}else{
|
||||
cont.defaults().size(120f).pad(5);
|
||||
float isize = 14f * 4;
|
||||
|
||||
imagebutton ho = new imagebutton("icon-host", isize, () -> {
|
||||
ui.host.show();
|
||||
});
|
||||
ho.text("$text.host").padTop(4f);
|
||||
ho.cell.disabled(b -> Net.active());
|
||||
|
||||
new imagebutton("icon-quit", isize, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.quit.confirm", () -> {
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
}).text("Quit").padTop(4f);
|
||||
|
||||
for(Element e : content().getChildren()){
|
||||
if(e instanceof ImageButton){
|
||||
group.add((ImageButton)e);
|
||||
}
|
||||
}
|
||||
|
||||
build.end();
|
||||
}
|
||||
}
|
||||
cont.addRowImageTextButton("$back", "icon-play-2", isize, this::hide);
|
||||
cont.addRowImageTextButton("$settings", "icon-tools", isize, ui.settings::show);
|
||||
|
||||
private void runExitSave(){
|
||||
if(control.getSaves().getCurrent() == null ||
|
||||
!control.getSaves().getCurrent().isAutosave()){
|
||||
state.set(State.menu);
|
||||
control.tutorial().reset();
|
||||
return;
|
||||
}
|
||||
if(!world.isZone() && !state.isEditor()){
|
||||
cont.addRowImageTextButton("$save", "icon-save", isize, save::show);
|
||||
|
||||
ui.loadfrag.show("$text.saveload");
|
||||
cont.row();
|
||||
|
||||
Timers.runTask(5f, () -> {
|
||||
ui.loadfrag.hide();
|
||||
try{
|
||||
control.getSaves().getCurrent().save();
|
||||
}catch(Throwable e){
|
||||
e = (e.getCause() == null ? e : e.getCause());
|
||||
ui.showError("[orange]"+ Bundles.get("text.savefail")+"\n[white]" + ClassReflection.getSimpleName(e.getClass()) + ": " + e.getMessage() + "\n" + "at " + e.getStackTrace()[0].getFileName() + ":" + e.getStackTrace()[0].getLineNumber());
|
||||
}
|
||||
state.set(State.menu);
|
||||
});
|
||||
}
|
||||
cont.addRowImageTextButton("$load", "icon-load", isize, load::show).disabled(b -> Net.active());
|
||||
}else{
|
||||
cont.row();
|
||||
}
|
||||
|
||||
cont.addRowImageTextButton("$hostserver.mobile", "icon-host", isize, ui.host::show).disabled(b -> Net.active());
|
||||
|
||||
cont.addRowImageTextButton("$quit", "icon-quit", isize, () -> {
|
||||
ui.showConfirm("$confirm", "$quit.confirm", () -> {
|
||||
wasClient = Net.client();
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void runExitSave(){
|
||||
if(state.isEditor() && !wasClient){
|
||||
ui.editor.resumeEditing();
|
||||
return;
|
||||
}
|
||||
|
||||
if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave()){
|
||||
state.set(State.menu);
|
||||
return;
|
||||
}
|
||||
|
||||
ui.loadAnd("$saveload", () -> {
|
||||
try{
|
||||
control.saves.getCurrent().save();
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
ui.showError("[accent]" + Core.bundle.get("savefail"));
|
||||
}
|
||||
state.set(State.menu);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.ucore.scene.ui.Dialog;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class RestartDialog extends Dialog {
|
||||
|
||||
public RestartDialog(){
|
||||
super("$text.gameover", "dialog");
|
||||
|
||||
shown(() -> {
|
||||
content().clearChildren();
|
||||
if(control.isHighScore()){
|
||||
content().add("$text.highscore").pad(6);
|
||||
content().row();
|
||||
}
|
||||
content().add("$text.lasted").pad(12).get();
|
||||
content().add("[accent]" + state.wave);
|
||||
pack();
|
||||
});
|
||||
|
||||
getButtonTable().addButton("$text.menu", ()-> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.ucore.scene.ui.Label;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class RollbackDialog extends FloatingDialog {
|
||||
|
||||
public RollbackDialog(){
|
||||
super("$text.server.rollback");
|
||||
|
||||
setup();
|
||||
shown(this::setup);
|
||||
}
|
||||
|
||||
private void setup(){
|
||||
content().clear();
|
||||
buttons().clear();
|
||||
|
||||
if(gwt) return;
|
||||
|
||||
content().row();
|
||||
content().add("$text.server.rollback.numberfield");
|
||||
|
||||
TextField field = content().addField("", t->{}).size(200f, 48f).get();
|
||||
field.setTextFieldFilter((f, c) -> field.getText().length() < 4);
|
||||
|
||||
content().row();
|
||||
buttons().defaults().size(200f, 50f).left().pad(2f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
|
||||
buttons().addButton("$text.ok", () -> {
|
||||
NetEvents.handleRollbackRequest(Integer.valueOf(field.getText()));
|
||||
hide();
|
||||
}).disabled(b -> field.getText().isEmpty() || !Strings.canParsePostiveInt(field.getText()));
|
||||
}
|
||||
}
|
||||
@@ -1,204 +1,261 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.event.InputEvent;
|
||||
import io.anuke.arc.scene.event.InputListener;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.SettingsDialog.SettingsTable.Setting;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.event.InputEvent;
|
||||
import io.anuke.ucore.scene.event.InputListener;
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.SettingsDialog;
|
||||
import io.anuke.ucore.scene.ui.Slider;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class SettingsMenuDialog extends SettingsDialog{
|
||||
public SettingsTable graphics;
|
||||
public SettingsTable game;
|
||||
public SettingsTable sound;
|
||||
public SettingsTable graphics;
|
||||
public SettingsTable game;
|
||||
public SettingsTable sound;
|
||||
|
||||
private Table prefs;
|
||||
private Table menu;
|
||||
private boolean wasPaused;
|
||||
|
||||
public SettingsMenuDialog(){
|
||||
setStyle(Core.skin.get("dialog", WindowStyle.class));
|
||||
private Table prefs;
|
||||
private Table menu;
|
||||
private boolean wasPaused;
|
||||
|
||||
hidden(() -> {
|
||||
if(!state.is(State.menu)){
|
||||
if(!wasPaused || Net.active())
|
||||
state.set(State.playing);
|
||||
}
|
||||
});
|
||||
public SettingsMenuDialog(){
|
||||
setStyle(Core.scene.skin.get("dialog", WindowStyle.class));
|
||||
|
||||
shown(() -> {
|
||||
if(!state.is(State.menu)){
|
||||
wasPaused = state.is(State.paused);
|
||||
if(ui.paused.getScene() != null){
|
||||
wasPaused = ui.paused.wasPaused;
|
||||
}
|
||||
if(!Net.active()) state.set(State.paused);
|
||||
ui.paused.hide();
|
||||
}
|
||||
});
|
||||
hidden(() -> {
|
||||
if(!state.is(State.menu)){
|
||||
if(!wasPaused || Net.active())
|
||||
state.set(State.playing);
|
||||
}
|
||||
});
|
||||
|
||||
setFillParent(true);
|
||||
title().setAlignment(Align.center);
|
||||
getTitleTable().row();
|
||||
getTitleTable().add(new Image("white"))
|
||||
.growX().height(3f).pad(4f).get().setColor(Colors.get("accent"));
|
||||
shown(() -> {
|
||||
if(!state.is(State.menu)){
|
||||
wasPaused = state.is(State.paused);
|
||||
state.set(State.paused);
|
||||
}
|
||||
});
|
||||
|
||||
content().clearChildren();
|
||||
content().remove();
|
||||
buttons().remove();
|
||||
setFillParent(true);
|
||||
title.setAlignment(Align.center);
|
||||
titleTable.row();
|
||||
titleTable.add(new Image("white")).growX().height(3f).pad(4f).get().setColor(Pal.accent);
|
||||
|
||||
menu = new Table();
|
||||
cont.clearChildren();
|
||||
cont.remove();
|
||||
buttons.remove();
|
||||
|
||||
Consumer<SettingsTable> s = table -> {
|
||||
table.row();
|
||||
table.addImageTextButton("$text.back", "icon-arrow-left", 10*3, this::back).size(240f, 60f).colspan(2).padTop(15f);
|
||||
};
|
||||
menu = new Table();
|
||||
|
||||
game = new SettingsTable(s);
|
||||
graphics = new SettingsTable(s);
|
||||
sound = new SettingsTable(s);
|
||||
Consumer<SettingsTable> s = table -> {
|
||||
table.row();
|
||||
table.addImageTextButton("$back", "icon-arrow-left", iconsize, this::back).size(240f, 60f).colspan(2).padTop(15f);
|
||||
};
|
||||
|
||||
prefs = new Table();
|
||||
prefs.top();
|
||||
prefs.margin(14f);
|
||||
game = new SettingsTable(s);
|
||||
graphics = new SettingsTable(s);
|
||||
sound = new SettingsTable(s);
|
||||
|
||||
menu.defaults().size(300f, 60f).pad(3f);
|
||||
menu.addButton("$text.settings.game", () -> visible(0));
|
||||
menu.row();
|
||||
menu.addButton("$text.settings.graphics", () -> visible(1));
|
||||
menu.row();
|
||||
menu.addButton("$text.settings.sound", () -> visible(2));
|
||||
if(!Vars.mobile) {
|
||||
menu.row();
|
||||
menu.addButton("$text.settings.controls", ui.controls::show);
|
||||
}
|
||||
menu.row();
|
||||
menu.addButton("$text.settings.language", ui.language::show);
|
||||
prefs = new Table();
|
||||
prefs.top();
|
||||
prefs.margin(14f);
|
||||
|
||||
prefs.clearChildren();
|
||||
prefs.add(menu);
|
||||
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));
|
||||
if(!Vars.mobile){
|
||||
menu.row();
|
||||
menu.addButton("$settings.controls", ui.controls::show);
|
||||
}
|
||||
menu.row();
|
||||
menu.addButton("$settings.language", ui.language::show);
|
||||
|
||||
ScrollPane pane = new ScrollPane(prefs, "clear");
|
||||
pane.addCaptureListener(new InputListener() {
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
|
||||
Element actor = pane.hit(x, y, true);
|
||||
if (actor instanceof Slider) {
|
||||
pane.setFlickScroll(false);
|
||||
return true;
|
||||
}
|
||||
prefs.clearChildren();
|
||||
prefs.add(menu);
|
||||
|
||||
return super.touchDown(event, x, y, pointer, button);
|
||||
}
|
||||
ScrollPane pane = new ScrollPane(prefs);
|
||||
pane.addCaptureListener(new InputListener(){
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
Element actor = pane.hit(x, y, true);
|
||||
if(actor instanceof Slider){
|
||||
pane.setFlickScroll(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
|
||||
pane.setFlickScroll(true);
|
||||
super.touchUp(event, x, y, pointer, button);
|
||||
}
|
||||
});
|
||||
pane.setFadeScrollBars(false);
|
||||
return super.touchDown(event, x, y, pointer, button);
|
||||
}
|
||||
|
||||
row();
|
||||
add(pane).grow().top();
|
||||
row();
|
||||
add(buttons()).fillX();
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
pane.setFlickScroll(true);
|
||||
super.touchUp(event, x, y, pointer, button);
|
||||
}
|
||||
});
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
hidden(this::back);
|
||||
row();
|
||||
add(pane).grow().top();
|
||||
row();
|
||||
add(buttons).fillX();
|
||||
|
||||
addSettings();
|
||||
}
|
||||
hidden(this::back);
|
||||
|
||||
void addSettings(){
|
||||
sound.volumePrefs();
|
||||
addSettings();
|
||||
}
|
||||
|
||||
game.screenshakePref();
|
||||
game.checkPref("smoothcam", true);
|
||||
game.checkPref("effects", true);
|
||||
game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%");
|
||||
game.sliderPref("saveinterval", 90, 10, 5*120, i -> Bundles.format("setting.seconds", i));
|
||||
void addSettings(){
|
||||
//TODO add when sound works again
|
||||
//sound.volumePrefs();
|
||||
sound.add("[LIGHT_GRAY]there is no sound implemented in v4 yet");
|
||||
|
||||
if(!gwt){
|
||||
graphics.checkPref("multithread", false, threads::setEnabled);
|
||||
game.screenshakePref();
|
||||
if(mobile){
|
||||
game.checkPref("autotarget", true);
|
||||
}
|
||||
game.sliderPref("saveinterval", 60, 10, 5 * 120, i -> Core.bundle.format("setting.seconds", i));
|
||||
|
||||
if(Settings.getBool("multithread")){
|
||||
threads.setEnabled(true);
|
||||
}
|
||||
}
|
||||
if(!mobile){
|
||||
game.checkPref("crashreport", true);
|
||||
}
|
||||
|
||||
if(!mobile && !gwt) {
|
||||
graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b));
|
||||
graphics.checkPref("fullscreen", false, b -> {
|
||||
if (b) {
|
||||
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
|
||||
} else {
|
||||
Gdx.graphics.setWindowedMode(600, 480);
|
||||
}
|
||||
});
|
||||
game.pref(new Setting(){
|
||||
@Override
|
||||
public void add(SettingsTable table){
|
||||
table.addButton("$settings.cleardata", () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("$settings.cleardata");
|
||||
dialog.setFillParent(false);
|
||||
dialog.cont.defaults().size(230f, 60f).pad(3);
|
||||
dialog.addCloseButton();
|
||||
dialog.cont.addButton("$settings.clearunlocks", () -> {
|
||||
ui.showConfirm("$confirm", "$settings.clear.confirm", () -> {
|
||||
data.reset();
|
||||
dialog.hide();
|
||||
});
|
||||
});
|
||||
dialog.cont.row();
|
||||
dialog.cont.addButton("$settings.clearall", () -> {
|
||||
ui.showConfirm("$confirm", "$settings.clearall.confirm", () -> {
|
||||
ObjectMap<String, Object> map = new ObjectMap<>();
|
||||
for(String value : Core.settings.keys()){
|
||||
if(value.contains("usid") || value.contains("uuid")){
|
||||
map.put(value, Core.settings.getString(value));
|
||||
}
|
||||
}
|
||||
Core.settings.clear();
|
||||
Core.settings.putAll(map);
|
||||
Core.settings.save();
|
||||
|
||||
Gdx.graphics.setVSync(Settings.getBool("vsync"));
|
||||
if(Settings.getBool("fullscreen")){
|
||||
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
|
||||
}
|
||||
}
|
||||
for(FileHandle file : dataDirectory.list()){
|
||||
file.deleteDirectory();
|
||||
}
|
||||
|
||||
graphics.checkPref("fps", false);
|
||||
graphics.checkPref("lasers", true);
|
||||
graphics.sliderPref("previewopacity", 50, 0, 100, i -> i + "%");
|
||||
graphics.checkPref("indicators", true);
|
||||
graphics.checkPref("healthbars", true);
|
||||
graphics.checkPref("pixelate", true, b -> {
|
||||
if(b){
|
||||
renderer.pixelSurface.setScale(Core.cameraScale);
|
||||
renderer.shadowSurface.setScale(Core.cameraScale);
|
||||
renderer.shieldSurface.setScale(Core.cameraScale);
|
||||
Graphics.getEffects1().setScale(Core.cameraScale);
|
||||
Graphics.getEffects2().setScale(Core.cameraScale);
|
||||
}else{
|
||||
renderer.shadowSurface.setScale(1);
|
||||
renderer.shieldSurface.setScale(1);
|
||||
Graphics.getEffects1().setScale(1);
|
||||
Graphics.getEffects2().setScale(1);
|
||||
}
|
||||
renderer.setPixelate(b);
|
||||
});
|
||||
}
|
||||
Core.app.exit();
|
||||
});
|
||||
});
|
||||
dialog.cont.row();
|
||||
dialog.show();
|
||||
}).size(220f, 60f).pad(6).left();
|
||||
table.add();
|
||||
table.row();
|
||||
}
|
||||
});
|
||||
|
||||
private void back(){
|
||||
prefs.clearChildren();
|
||||
prefs.add(menu);
|
||||
}
|
||||
graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Core.bundle.get("setting.fpscap.none") : Core.bundle.format("setting.fpscap.text", s)));
|
||||
graphics.sliderPref("chatopacity", 100, 0, 100, 5, s -> s + "%");
|
||||
|
||||
private void visible(int index){
|
||||
prefs.clearChildren();
|
||||
Table table = Mathf.select(index, game, graphics, sound);
|
||||
if(!mobile){
|
||||
graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b));
|
||||
graphics.checkPref("fullscreen", false, b -> {
|
||||
if(b){
|
||||
Core.graphics.setFullscreenMode(Core.graphics.getDisplayMode());
|
||||
}else{
|
||||
Core.graphics.setWindowedMode(600, 480);
|
||||
}
|
||||
});
|
||||
|
||||
graphics.checkPref("borderlesswindow", false, b -> Core.graphics.setUndecorated(b));
|
||||
|
||||
Core.graphics.setVSync(Core.settings.getBool("vsync"));
|
||||
if(Core.settings.getBool("fullscreen")){
|
||||
Core.graphics.setFullscreenMode(Core.graphics.getDisplayMode());
|
||||
}
|
||||
|
||||
if(Core.settings.getBool("borderlesswindow")){
|
||||
Core.graphics.setUndecorated(true);
|
||||
}
|
||||
}else{
|
||||
graphics.checkPref("landscape", false, b -> {
|
||||
if(b){
|
||||
Platform.instance.beginForceLandscape();
|
||||
}else{
|
||||
Platform.instance.endForceLandscape();
|
||||
}
|
||||
});
|
||||
|
||||
if(Core.settings.getBool("landscape")){
|
||||
Platform.instance.beginForceLandscape();
|
||||
}
|
||||
}
|
||||
|
||||
graphics.checkPref("effects", true);
|
||||
graphics.checkPref("playerchat", true);
|
||||
graphics.checkPref("minimap", !mobile);
|
||||
graphics.checkPref("fps", false);
|
||||
graphics.checkPref("indicators", true);
|
||||
graphics.checkPref("animatedwater", false);
|
||||
graphics.checkPref("animatedshields", !mobile);
|
||||
graphics.checkPref("lasers", true);
|
||||
graphics.checkPref("pixelate", false);
|
||||
|
||||
//TODO is this necessary?
|
||||
/*
|
||||
graphics.checkPref("linear", false, b -> {
|
||||
for(Texture tex : Core.atlas.getTextures()){
|
||||
TextureFilter filter = b ? TextureFilter.Linear : TextureFilter.Nearest;
|
||||
tex.setFilter(filter, filter);
|
||||
}
|
||||
});
|
||||
|
||||
if(Core.settings.getBool("linear")){
|
||||
for(Texture tex : Core.atlas.getTextures()){
|
||||
TextureFilter filter = TextureFilter.Linear;
|
||||
tex.setFilter(filter, filter);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void back(){
|
||||
prefs.clearChildren();
|
||||
prefs.add(menu);
|
||||
}
|
||||
|
||||
private void visible(int index){
|
||||
prefs.clearChildren();
|
||||
Table table = new Table[]{game, graphics, sound}[index];
|
||||
prefs.add(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCloseButton(){
|
||||
buttons().addImageTextButton("$text.menu", "icon-arrow-left", 30f, this::hide).size(230f, 64f);
|
||||
|
||||
keyDown(key->{
|
||||
if(key == Keys.ESCAPE || key == Keys.BACK)
|
||||
hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCloseButton(){
|
||||
buttons.addImageTextButton("$menu", "icon-arrow-left", 30f, this::hide).size(230f, 64f);
|
||||
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK)
|
||||
hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
317
core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java
Normal file
317
core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java
Normal file
@@ -0,0 +1,317 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.actions.Actions;
|
||||
import io.anuke.arc.scene.actions.RelativeTemporalAction;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.style.TextureRegionDrawable;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.mindustry.content.TechTree;
|
||||
import io.anuke.mindustry.content.TechTree.TechNode;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.ui.ItemsDisplay;
|
||||
import io.anuke.mindustry.ui.TreeLayout;
|
||||
import io.anuke.mindustry.ui.TreeLayout.TreeNode;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class TechTreeDialog extends FloatingDialog{
|
||||
private final float nodeSize = Unit.dp.scl(60f);
|
||||
private ObjectSet<TechTreeNode> nodes = new ObjectSet<>();
|
||||
private TechTreeNode root = new TechTreeNode(TechTree.root, null);
|
||||
private ItemsDisplay items;
|
||||
|
||||
public TechTreeDialog(){
|
||||
super("");
|
||||
|
||||
titleTable.remove();
|
||||
margin(0f).marginBottom(8);
|
||||
cont.stack(new View(), items = new ItemsDisplay()).grow();
|
||||
|
||||
shown(() -> {
|
||||
checkNodes(root);
|
||||
treeLayout();
|
||||
});
|
||||
|
||||
hidden(ui.deploy::setup);
|
||||
|
||||
addCloseButton();
|
||||
|
||||
buttons.addImageTextButton("$database", "icon-database", iconsize, () -> {
|
||||
hide();
|
||||
ui.database.show();
|
||||
}).size(210f, 64f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(float x, float y){
|
||||
drawDefaultBackground(x, y);
|
||||
}
|
||||
|
||||
void treeLayout(){
|
||||
TreeLayout layout = new TreeLayout();
|
||||
layout.gapBetweenLevels = Unit.dp.scl(60f);
|
||||
layout.gapBetweenNodes = Unit.dp.scl(40f);
|
||||
LayoutNode node = new LayoutNode(root, null);
|
||||
layout.layout(node);
|
||||
copyInfo(node);
|
||||
}
|
||||
|
||||
void copyInfo(LayoutNode node){
|
||||
node.node.x = node.x;
|
||||
node.node.y = node.y;
|
||||
if(node.children != null){
|
||||
for(LayoutNode child : node.children){
|
||||
copyInfo(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkNodes(TechTreeNode node){
|
||||
boolean locked = locked(node.node);
|
||||
if(!locked) node.visible = true;
|
||||
for(TechTreeNode l : node.children){
|
||||
l.visible = !locked;
|
||||
checkNodes(l);
|
||||
}
|
||||
|
||||
items.rebuild();
|
||||
}
|
||||
|
||||
void showToast(String info){
|
||||
Table table = new Table();
|
||||
table.actions(Actions.fadeOut(0.5f, Interpolation.fade), Actions.remove());
|
||||
table.top().add(info);
|
||||
table.setName("toast");
|
||||
table.update(() -> {
|
||||
table.toFront();
|
||||
table.setPosition(Core.graphics.getWidth() / 2f, Core.graphics.getHeight() - 21, Align.top);
|
||||
});
|
||||
Core.scene.add(table);
|
||||
}
|
||||
|
||||
boolean locked(TechNode node){
|
||||
return node.block.locked();
|
||||
}
|
||||
|
||||
class LayoutNode extends TreeNode<LayoutNode>{
|
||||
final TechTreeNode node;
|
||||
|
||||
LayoutNode(TechTreeNode node, LayoutNode parent){
|
||||
this.node = node;
|
||||
this.parent = parent;
|
||||
this.width = this.height = nodeSize;
|
||||
if(node.children != null){
|
||||
children = Array.with(node.children).select(n -> n.visible).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TechTreeNode extends TreeNode<TechTreeNode>{
|
||||
final TechNode node;
|
||||
boolean visible = true;
|
||||
|
||||
TechTreeNode(TechNode node, TechTreeNode parent){
|
||||
this.node = node;
|
||||
this.parent = parent;
|
||||
this.width = this.height = nodeSize;
|
||||
nodes.add(this);
|
||||
if(node.children != null){
|
||||
children = new TechTreeNode[node.children.size];
|
||||
for(int i = 0; i < children.length; i++){
|
||||
children[i] = new TechTreeNode(node.children.get(i), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class View extends Group{
|
||||
float panX = 0, panY = -200;
|
||||
boolean moved = false;
|
||||
ImageButton hoverNode;
|
||||
Table infoTable = new Table();
|
||||
|
||||
{
|
||||
infoTable.touchable(Touchable.enabled);
|
||||
|
||||
for(TechTreeNode node : nodes){
|
||||
ImageButton button = new ImageButton(node.node.block.icon(Icon.medium), "node");
|
||||
button.visible(() -> node.visible);
|
||||
button.clicked(() -> {
|
||||
if(mobile){
|
||||
hoverNode = button;
|
||||
rebuild();
|
||||
float right = infoTable.getRight();
|
||||
if(right > Core.graphics.getWidth()){
|
||||
float moveBy = right - Core.graphics.getWidth();
|
||||
addAction(new RelativeTemporalAction(){
|
||||
{
|
||||
setDuration(0.1f);
|
||||
setInterpolation(Interpolation.fade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRelative(float percentDelta){
|
||||
panX -= moveBy * percentDelta;
|
||||
}
|
||||
});
|
||||
}
|
||||
}else if(data.hasItems(node.node.requirements) && locked(node.node)){
|
||||
unlock(node.node);
|
||||
}
|
||||
});
|
||||
button.hovered(() -> {
|
||||
if(!mobile && hoverNode != button && node.visible){
|
||||
hoverNode = button;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
button.exited(() -> {
|
||||
if(!mobile && hoverNode == button && !infoTable.hasMouse() && !hoverNode.hasMouse()){
|
||||
hoverNode = null;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
button.touchable(() -> !node.visible ? Touchable.disabled : Touchable.enabled);
|
||||
button.setUserObject(node.node);
|
||||
button.tapped(() -> moved = false);
|
||||
button.setSize(nodeSize);
|
||||
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");
|
||||
((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);
|
||||
});
|
||||
addChild(button);
|
||||
}
|
||||
|
||||
if(mobile){
|
||||
tapped(() -> {
|
||||
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(e == this){
|
||||
hoverNode = null;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dragged((x, y) -> {
|
||||
moved = true;
|
||||
panX += x;
|
||||
panY += y;
|
||||
});
|
||||
}
|
||||
|
||||
void unlock(TechNode node){
|
||||
data.unlockContent(node.block);
|
||||
data.removeItems(node.requirements);
|
||||
showToast(Core.bundle.format("researched", node.block.localizedName));
|
||||
checkNodes(root);
|
||||
hoverNode = null;
|
||||
treeLayout();
|
||||
rebuild();
|
||||
Core.scene.act();
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
ImageButton button = hoverNode;
|
||||
|
||||
infoTable.remove();
|
||||
infoTable.clear();
|
||||
infoTable.update(null);
|
||||
|
||||
if(button == null) return;
|
||||
|
||||
TechNode node = (TechNode)button.getUserObject();
|
||||
|
||||
infoTable.exited(() -> {
|
||||
if(hoverNode == button && !infoTable.hasMouse() && !hoverNode.hasMouse()){
|
||||
hoverNode = null;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
|
||||
infoTable.update(() -> infoTable.setPosition(button.getX() + button.getWidth(), button.getY() + button.getHeight(), Align.topLeft));
|
||||
|
||||
infoTable.left();
|
||||
|
||||
infoTable.table("content-background", b -> {
|
||||
b.margin(0).left().defaults().left();
|
||||
|
||||
b.addImageButton("icon-info", "node", iconsize, () -> ui.content.show(node.block)).growY().width(50f);
|
||||
b.add().grow();
|
||||
b.table(desc -> {
|
||||
desc.left().defaults().left();
|
||||
desc.add(node.block.localizedName);
|
||||
desc.row();
|
||||
if(locked(node)){
|
||||
desc.table(t -> {
|
||||
t.left();
|
||||
for(ItemStack req : node.requirements){
|
||||
t.table(list -> {
|
||||
list.left();
|
||||
list.addImage(req.item.getContentIcon()).size(8 * 3).padRight(3);
|
||||
list.add(req.item.localizedName()).color(Color.LIGHT_GRAY);
|
||||
list.label(() -> " " + Math.min(data.getItem(req.item), req.amount) + " / " + req.amount)
|
||||
.update(l -> l.setColor(data.has(req.item, req.amount) ? Color.LIGHT_GRAY : Color.SCARLET));
|
||||
}).fillX().left();
|
||||
t.row();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
desc.add("$completed");
|
||||
}
|
||||
}).pad(9);
|
||||
|
||||
if(mobile && locked(node)){
|
||||
b.row();
|
||||
b.addImageTextButton("$research", "icon-check", "node", iconsize, () -> 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();
|
||||
}
|
||||
|
||||
|
||||
addChild(infoTable);
|
||||
infoTable.pack();
|
||||
infoTable.act(Core.graphics.getDeltaTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float offsetX = panX + width / 2f + x, offsetY = panY + height / 2f + y;
|
||||
|
||||
for(TechTreeNode node : nodes){
|
||||
if(!node.visible) continue;
|
||||
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.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,42 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.net.TraceInfo;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.net.Administration.TraceInfo;
|
||||
|
||||
public class TraceDialog extends FloatingDialog {
|
||||
public class TraceDialog extends FloatingDialog{
|
||||
|
||||
public TraceDialog(){
|
||||
super("$text.trace");
|
||||
super("$trace");
|
||||
|
||||
addCloseButton();
|
||||
setFillParent(false);
|
||||
}
|
||||
|
||||
public void show(Player player, TraceInfo info){
|
||||
content().clear();
|
||||
cont.clear();
|
||||
|
||||
Table table = new Table("button");
|
||||
Table table = new Table("clear");
|
||||
table.margin(14);
|
||||
table.defaults().pad(1);
|
||||
|
||||
table.defaults().left();
|
||||
table.add(Bundles.format("text.trace.playername", player.name));
|
||||
table.add(Core.bundle.format("trace.playername", player.name));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.ip", info.ip));
|
||||
table.add(Core.bundle.format("trace.ip", info.ip));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.id", info.uuid));
|
||||
table.add(Core.bundle.format("trace.id", info.uuid));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.modclient", info.modclient));
|
||||
table.add(Core.bundle.format("trace.modclient", info.modded));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.android", info.android));
|
||||
table.add(Core.bundle.format("trace.mobile", info.mobile));
|
||||
table.row();
|
||||
|
||||
table.add().pad(5);
|
||||
table.row();
|
||||
|
||||
table.add(Bundles.format("text.trace.totalblocksbroken", info.totalBlocksBroken));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.structureblocksbroken", info.structureBlocksBroken));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.lastblockbroken", info.lastBlockBroken.formalName));
|
||||
table.row();
|
||||
|
||||
table.add().pad(5);
|
||||
table.row();
|
||||
|
||||
table.add(Bundles.format("text.trace.totalblocksplaced", info.totalBlocksPlaced));
|
||||
table.row();
|
||||
table.add(Bundles.format("text.trace.lastblockplaced", info.lastBlockPlaced.formalName));
|
||||
table.row();
|
||||
|
||||
content().add(table);
|
||||
cont.add(table);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
163
core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java
Normal file
163
core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.Button;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.type.Zone.ZoneRequirement;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ZoneInfoDialog extends FloatingDialog{
|
||||
private ZoneLoadoutDialog loadout = new ZoneLoadoutDialog();
|
||||
|
||||
public ZoneInfoDialog(){
|
||||
super("");
|
||||
|
||||
titleTable.remove();
|
||||
addCloseButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(float x, float y){
|
||||
drawDefaultBackground(x, y);
|
||||
}
|
||||
|
||||
public void show(Zone zone){
|
||||
setup(zone);
|
||||
show();
|
||||
}
|
||||
|
||||
private void setup(Zone zone){
|
||||
cont.clear();
|
||||
|
||||
Table iteminfo = new Table();
|
||||
Runnable rebuildItems = () -> {
|
||||
int i = 0;
|
||||
iteminfo.clear();
|
||||
|
||||
if(!zone.unlocked()) return;
|
||||
|
||||
ItemStack[] stacks = zone.getLaunchCost();
|
||||
for(ItemStack stack : stacks){
|
||||
if(stack.amount == 0) continue;
|
||||
|
||||
if(i++ % 2 == 0){
|
||||
iteminfo.row();
|
||||
}
|
||||
iteminfo.addImage(stack.item.icon(Item.Icon.medium)).size(8 * 3).padRight(1);
|
||||
iteminfo.add(stack.amount + "").color(Color.LIGHT_GRAY).padRight(5);
|
||||
}
|
||||
};
|
||||
|
||||
rebuildItems.run();
|
||||
|
||||
cont.table(cont -> {
|
||||
if(zone.locked()){
|
||||
cont.addImage("icon-locked");
|
||||
cont.row();
|
||||
cont.add("$locked").padBottom(6);
|
||||
cont.row();
|
||||
|
||||
cont.table(req -> {
|
||||
req.defaults().left();
|
||||
|
||||
if(zone.zoneRequirements.length > 0){
|
||||
req.table(r -> {
|
||||
r.add("$complete").colspan(2).left();
|
||||
r.row();
|
||||
for(ZoneRequirement other : zone.zoneRequirements){
|
||||
r.addImage("icon-terrain").padRight(4);
|
||||
r.add(Core.bundle.format("zone.requirement", other.wave, other.zone.localizedName())).color(Color.LIGHT_GRAY);
|
||||
r.addImage(other.zone.bestWave() >= other.wave ? "icon-check" : "icon-cancel")
|
||||
.color(other.zone.bestWave() >= other.wave ? Color.LIGHT_GRAY : Color.SCARLET).padLeft(3);
|
||||
r.row();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
req.row();
|
||||
|
||||
if(zone.blockRequirements.length > 0){
|
||||
req.table(r -> {
|
||||
r.add("$research.list").colspan(2).left();
|
||||
r.row();
|
||||
for(Block block : zone.blockRequirements){
|
||||
r.addImage(block.icon(Icon.small)).size(8 * 3).padRight(4);
|
||||
r.add(block.localizedName).color(Color.LIGHT_GRAY);
|
||||
r.addImage(data.isUnlocked(block) ? "icon-check" : "icon-cancel")
|
||||
.color(data.isUnlocked(block) ? Color.LIGHT_GRAY : Color.SCARLET).padLeft(3);
|
||||
r.row();
|
||||
}
|
||||
|
||||
}).padTop(10);
|
||||
}
|
||||
}).growX();
|
||||
|
||||
}else{
|
||||
cont.add(zone.localizedName()).color(Pal.accent).growX().center();
|
||||
cont.row();
|
||||
cont.addImage("white").color(Pal.accent).height(3).pad(6).growX();
|
||||
cont.row();
|
||||
cont.addButton(zone.canConfigure() ? "$configure" : Core.bundle.format("configure.locked", zone.configureWave), () -> loadout.show(zone, rebuildItems)).fillX().pad(3).disabled(b -> !zone.canConfigure());
|
||||
cont.row();
|
||||
cont.table(res -> {
|
||||
res.add("$zone.resources").padRight(6);
|
||||
if(zone.resources.length > 0){
|
||||
for(Item item : zone.resources){
|
||||
res.addImage(item.icon(Item.Icon.medium)).size(8 * 3);
|
||||
}
|
||||
}else{
|
||||
res.add("$none");
|
||||
}
|
||||
});
|
||||
|
||||
if(zone.bestWave() > 0){
|
||||
cont.row();
|
||||
cont.add(Core.bundle.format("bestwave", zone.bestWave()));
|
||||
}
|
||||
}
|
||||
});
|
||||
cont.row();
|
||||
|
||||
Button button = cont.addButton(zone.locked() ? "$uncover" : "$launch", () -> {
|
||||
if(!data.isUnlocked(zone)){
|
||||
data.unlockContent(zone);
|
||||
ui.deploy.setup();
|
||||
setup(zone);
|
||||
}else{
|
||||
ui.deploy.hide();
|
||||
data.removeItems(zone.getLaunchCost());
|
||||
hide();
|
||||
control.playZone(zone);
|
||||
}
|
||||
}).minWidth(150f).margin(13f).padTop(5).disabled(b -> zone.locked() ? !canUnlock(zone) : !data.hasItems(zone.getLaunchCost())).uniformY().get();
|
||||
|
||||
button.row();
|
||||
button.add(iteminfo);
|
||||
}
|
||||
|
||||
private boolean canUnlock(Zone zone){
|
||||
if(data.isUnlocked(zone)){
|
||||
return true;
|
||||
}
|
||||
|
||||
for(ZoneRequirement other : zone.zoneRequirements){
|
||||
if(other.zone.bestWave() < other.wave){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for(Block other : zone.blockRequirements){
|
||||
if(!data.isUnlocked(other)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.data;
|
||||
|
||||
public class ZoneLoadoutDialog extends FloatingDialog{
|
||||
private Zone zone;
|
||||
private Runnable hider;
|
||||
|
||||
public ZoneLoadoutDialog(){
|
||||
super("$configure");
|
||||
setFillParent(false);
|
||||
addCloseButton();
|
||||
shown(this::setup);
|
||||
hidden(() -> {
|
||||
if(hider != null){
|
||||
hider.run();
|
||||
}
|
||||
});
|
||||
buttons.row();
|
||||
buttons.addButton("$settings.reset", () -> {
|
||||
zone.resetStartingItems();
|
||||
zone.updateLaunchCost();
|
||||
setup();
|
||||
}).size(210f, 64f);
|
||||
}
|
||||
|
||||
public void show(Zone zone, Runnable hider){
|
||||
this.hider = hider;
|
||||
this.zone = zone;
|
||||
show();
|
||||
}
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
float bsize = 40f;
|
||||
int step = 50;
|
||||
|
||||
for(ItemStack stack : zone.getStartingItems()){
|
||||
cont.addButton("x", "clear-partial", () -> {
|
||||
zone.getStartingItems().remove(stack);
|
||||
zone.updateLaunchCost();
|
||||
setup();
|
||||
}).size(bsize);
|
||||
|
||||
cont.addButton("-", "clear-partial", () -> {
|
||||
stack.amount = Math.max(stack.amount - step, 0);
|
||||
zone.updateLaunchCost();
|
||||
}).size(bsize);
|
||||
cont.addButton("+", "clear-partial", () -> {
|
||||
stack.amount = Math.min(stack.amount + step, zone.loadout.core().itemCapacity);
|
||||
zone.updateLaunchCost();
|
||||
}).size(bsize);
|
||||
|
||||
cont.addImage(stack.item.icon(Item.Icon.medium)).size(8 * 3).padRight(4);
|
||||
cont.label(() -> stack.amount + "").left();
|
||||
|
||||
cont.row();
|
||||
}
|
||||
|
||||
cont.addButton("$add", () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("");
|
||||
dialog.setFillParent(false);
|
||||
for(Item item : content.items().select(item -> data.getItem(item) > 0 && item.type == ItemType.material && zone.getStartingItems().find(stack -> stack.item == item) == null)){
|
||||
TextButton button = dialog.cont.addButton("", "clear", () -> {
|
||||
zone.getStartingItems().add(new ItemStack(item, 0));
|
||||
zone.updateLaunchCost();
|
||||
setup();
|
||||
dialog.hide();
|
||||
}).size(300f, 36f).get();
|
||||
button.clearChildren();
|
||||
button.left();
|
||||
button.addImage(item.icon(Item.Icon.medium)).size(8 * 3).pad(4);
|
||||
button.add(item.localizedName);
|
||||
dialog.cont.row();
|
||||
}
|
||||
dialog.show();
|
||||
}).colspan(4).size(100f, bsize).left().disabled(b -> !content.items().contains(item -> data.getItem(item) > 0 && item.type == ItemType.material && !zone.getStartingItems().contains(stack -> stack.item == item)));
|
||||
pack();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,33 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
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.ucore.core.Core;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
|
||||
public class BackgroundFragment implements Fragment {
|
||||
public class BackgroundFragment extends Fragment{
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
|
||||
public void build(Group parent){
|
||||
Core.scene.table().addRect((a, b, w, h) -> {
|
||||
Draw.color();
|
||||
Draw.colorl(0.1f);
|
||||
Fill.crect(0, 0, w, h);
|
||||
Draw.shader(Shaders.menu);
|
||||
Fill.crect(0, 0, w, h);
|
||||
Draw.shader();
|
||||
|
||||
TextureRegion back = Draw.region("background");
|
||||
float backscl = (int)Math.max(Gdx.graphics.getWidth() / (float)back.getRegionWidth() * 1.5f, Unit.dp.scl(5f));
|
||||
|
||||
Draw.alpha(0.5f);
|
||||
Core.batch.draw(back, w/2 - back.getRegionWidth()*backscl/2, h/2 - back.getRegionHeight()*backscl/2,
|
||||
back.getRegionWidth()*backscl, back.getRegionHeight()*backscl);
|
||||
|
||||
boolean portrait = Gdx.graphics.getWidth() < Gdx.graphics.getHeight();
|
||||
float logoscl = (int)Unit.dp.scl(7) * (portrait ? 5f/7f : 1f);
|
||||
TextureRegion logo = Core.skin.getRegion("logotext");
|
||||
float logow = logo.getRegionWidth()*logoscl;
|
||||
float logoh = logo.getRegionHeight()*logoscl;
|
||||
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();
|
||||
Core.batch.draw(logo, (int)(w/2 - logow/2), (int)(h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 0)), logow, logoh);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.actions.Actions;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.actions.Actions;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
public class BlockConfigFragment implements Fragment {
|
||||
private Table table;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class BlockConfigFragment extends Fragment{
|
||||
private Table table = new Table();
|
||||
private Tile configTile;
|
||||
private Block configBlock;
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
table = new Table();
|
||||
Core.scene.add(table);
|
||||
public void build(Group parent){
|
||||
table.visible(false);
|
||||
parent.addChild(table);
|
||||
}
|
||||
|
||||
public boolean isShown(){
|
||||
@@ -32,30 +36,43 @@ public class BlockConfigFragment implements Fragment {
|
||||
|
||||
public void showConfig(Tile tile){
|
||||
configTile = tile;
|
||||
configBlock = tile.block();
|
||||
|
||||
table.visible(true);
|
||||
table.clear();
|
||||
tile.block().buildTable(tile, table);
|
||||
table.pack();
|
||||
table.setTransform(true);
|
||||
table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true),
|
||||
Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out));
|
||||
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;
|
||||
}
|
||||
|
||||
table.update(()->{
|
||||
table.setOrigin(Align.center);
|
||||
Vector2 pos = Graphics.screen(tile.drawx(), tile.drawy());
|
||||
table.setPosition(pos.x, pos.y, Align.center);
|
||||
if(configTile == null || configTile.block() == Blocks.air){
|
||||
Vector2 pos = Core.input.mouseScreen(tile.drawx(), tile.drawy() - tile.block().size * tilesize / 2f - 1);
|
||||
table.setPosition(pos.x, pos.y, Align.top);
|
||||
if(configTile == null || configTile.block() == Blocks.air || configTile.block() != configBlock){
|
||||
hideConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasConfigMouse(){
|
||||
Element e = Core.scene.hit(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY(), true);
|
||||
Element e = Core.scene.hit(Core.input.mouseX(), Core.graphics.getHeight() - Core.input.mouseY(), true);
|
||||
return e != null && (e == table || e.isDescendantOf(table));
|
||||
}
|
||||
|
||||
public void hideConfig(){
|
||||
configTile = null;
|
||||
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.visible(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.function.BooleanProvider;
|
||||
import io.anuke.arc.function.Supplier;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.actions.Actions;
|
||||
import io.anuke.arc.scene.event.*;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Item.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class BlockInventoryFragment extends Fragment{
|
||||
private final static float holdWithdraw = 20f;
|
||||
|
||||
private Table table;
|
||||
private Tile tile;
|
||||
private float holdTime = 0f;
|
||||
private boolean holding;
|
||||
private Item lastItem;
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
||||
public static void requestItem(Player player, Tile tile, Item item, int amount){
|
||||
if(player == null || tile == null) return;
|
||||
|
||||
int removed = tile.block().removeStack(tile, item, amount);
|
||||
|
||||
player.addItem(item, removed);
|
||||
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
||||
Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
table = new Table();
|
||||
table.visible(() -> !state.is(State.menu));
|
||||
table.setTransform(true);
|
||||
parent.setTransform(true);
|
||||
parent.addChild(table);
|
||||
}
|
||||
|
||||
public void showFor(Tile t){
|
||||
if(this.tile == t){
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
this.tile = t;
|
||||
if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0)
|
||||
return;
|
||||
rebuild(true);
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.visible(false), Actions.run(() -> {
|
||||
table.clear();
|
||||
table.update(null);
|
||||
}));
|
||||
table.touchable(Touchable.disabled);
|
||||
tile = null;
|
||||
}
|
||||
|
||||
private void rebuild(boolean actions){
|
||||
|
||||
IntSet container = new IntSet();
|
||||
|
||||
table.clearChildren();
|
||||
table.background("inventory");
|
||||
table.touchable(Touchable.enabled);
|
||||
table.update(() -> {
|
||||
if(state.is(State.menu) || tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0){
|
||||
hide();
|
||||
}else{
|
||||
if(holding && lastItem != null){
|
||||
holdTime += Time.delta();
|
||||
|
||||
if(holdTime >= holdWithdraw){
|
||||
int amount = Math.min(tile.entity.items.get(lastItem), player.maxAccepted(lastItem));
|
||||
Call.requestItem(player, tile, lastItem, amount);
|
||||
holding = false;
|
||||
holdTime = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
updateTablePosition();
|
||||
if(tile.block().hasItems){
|
||||
for(int i = 0; i < content.items().size; i++){
|
||||
boolean has = tile.entity.items.has(content.item(i));
|
||||
if(has != container.contains(i)){
|
||||
rebuild(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
int cols = 3;
|
||||
int row = 0;
|
||||
|
||||
table.margin(4f);
|
||||
table.defaults().size(8 * 5).pad(4f);
|
||||
|
||||
if(tile.block().hasItems){
|
||||
|
||||
for(int i = 0; i < content.items().size; i++){
|
||||
Item item = content.item(i);
|
||||
if(!tile.entity.items.has(item)) continue;
|
||||
|
||||
container.add(i);
|
||||
|
||||
BooleanProvider canPick = () -> player.acceptsItem(item) && !state.isPaused();
|
||||
|
||||
HandCursorListener l = new HandCursorListener();
|
||||
l.setEnabled(canPick);
|
||||
|
||||
Element image = itemImage(item.icon(Icon.xlarge), () -> {
|
||||
if(tile == null || tile.entity == null){
|
||||
return "";
|
||||
}
|
||||
return round(tile.entity.items.get(item));
|
||||
});
|
||||
image.addListener(l);
|
||||
|
||||
image.addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
if(!canPick.get() || !tile.entity.items.has(item)) return false;
|
||||
int amount = Math.min(1, player.maxAccepted(item));
|
||||
if(amount > 0){
|
||||
Call.requestItem(player, tile, item, amount);
|
||||
lastItem = item;
|
||||
holding = true;
|
||||
holdTime = 0f;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
holding = false;
|
||||
lastItem = null;
|
||||
}
|
||||
});
|
||||
table.add(image);
|
||||
|
||||
if(row++ % cols == cols - 1) table.row();
|
||||
}
|
||||
}
|
||||
|
||||
if(row == 0){
|
||||
table.setSize(0f, 0f);
|
||||
}
|
||||
|
||||
updateTablePosition();
|
||||
|
||||
if(actions){
|
||||
table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true),
|
||||
Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out));
|
||||
}
|
||||
}
|
||||
|
||||
private String round(float f){
|
||||
f = (int)f;
|
||||
if(f >= 1000000){
|
||||
return (int)(f / 1000000f) + "[gray]mil[]";
|
||||
}else if(f >= 1000){
|
||||
return (int)(f / 1000) + "k";
|
||||
}else{
|
||||
return (int)f + "";
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTablePosition(){
|
||||
Vector2 v = Core.input.mouseScreen(tile.drawx() + tile.block().size * tilesize / 2f, tile.drawy() + tile.block().size * tilesize / 2f);
|
||||
table.pack();
|
||||
table.setPosition(v.x, v.y, Align.topLeft);
|
||||
}
|
||||
|
||||
private Element itemImage(TextureRegion region, Supplier<CharSequence> text){
|
||||
Stack stack = new Stack();
|
||||
|
||||
Table t = new Table().left().bottom();
|
||||
t.label(text);
|
||||
|
||||
stack.add(new Image(region));
|
||||
stack.add(t);
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
@@ -1,420 +0,0 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.net.EditLog;
|
||||
import io.anuke.mindustry.resource.*;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Hue;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.actions.Actions;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.event.ClickListener;
|
||||
import io.anuke.ucore.scene.event.InputEvent;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.*;
|
||||
import io.anuke.ucore.scene.ui.layout.Stack;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class BlocksFragment implements Fragment{
|
||||
private Table desctable, itemtable, blocks, weapons;
|
||||
private Stack stack = new Stack();
|
||||
private Array<String> statlist = new Array<>();
|
||||
private boolean shown = true;
|
||||
private Recipe hoveredDescriptionRecipe;
|
||||
|
||||
public void build(){
|
||||
InputHandler input = control.input();
|
||||
|
||||
new table(){{
|
||||
abottom();
|
||||
aright();
|
||||
|
||||
visible(() -> !state.is(State.menu) && shown);
|
||||
|
||||
blocks = new table(){{
|
||||
|
||||
itemtable = new Table("button");
|
||||
itemtable.setVisible(() -> input.recipe == null && !state.mode.infiniteResources);
|
||||
|
||||
desctable = new Table("button");
|
||||
desctable.setVisible(() -> hoveredDescriptionRecipe != null || input.recipe != null);
|
||||
desctable.update(() -> {
|
||||
// note: This is required because there is no direct connection between
|
||||
// input.recipe and the description ui. If input.recipe gets set to null
|
||||
// a proper cleanup of the ui elements is required.
|
||||
boolean anyRecipeShown = input.recipe != null || hoveredDescriptionRecipe != null;
|
||||
boolean descriptionTableClean = desctable.getChildren().size == 0;
|
||||
boolean cleanupRequired = !anyRecipeShown && !descriptionTableClean;
|
||||
if(cleanupRequired){
|
||||
desctable.clear();
|
||||
}
|
||||
});
|
||||
|
||||
stack.add(itemtable);
|
||||
stack.add(desctable);
|
||||
|
||||
add(stack).fillX().uniformX();
|
||||
|
||||
row();
|
||||
|
||||
new table("pane") {{
|
||||
touchable(Touchable.enabled);
|
||||
int rows = 4;
|
||||
int maxcol = 0;
|
||||
float size = 48;
|
||||
|
||||
Stack stack = new Stack();
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
Array<Recipe> recipes = new Array<>();
|
||||
|
||||
for (Section sec : Section.values()) {
|
||||
recipes.clear();
|
||||
Recipes.getBy(sec, recipes);
|
||||
maxcol = Math.max((int) ((float) recipes.size / rows + 1), maxcol);
|
||||
}
|
||||
|
||||
for (Section sec : Section.values()) {
|
||||
recipes.clear();
|
||||
Recipes.getBy(sec, recipes);
|
||||
|
||||
Table table = new Table();
|
||||
|
||||
ImageButton button = new ImageButton("icon-" + sec.name(), "toggle");
|
||||
button.clicked(() -> {
|
||||
if (!table.isVisible() && input.recipe != null) {
|
||||
input.recipe = null;
|
||||
}
|
||||
});
|
||||
button.setName("sectionbutton" + sec.name());
|
||||
add(button).growX().height(54).padLeft(-1).padTop(sec.ordinal() <= 2 ? -10 : -5);
|
||||
button.getImageCell().size(40).padBottom(4).padTop(2);
|
||||
group.add(button);
|
||||
|
||||
if (sec.ordinal() % 3 == 2 && sec.ordinal() > 0) {
|
||||
row();
|
||||
}
|
||||
|
||||
table.margin(4);
|
||||
table.top().left();
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (Recipe r : recipes) {
|
||||
TextureRegion region = Draw.hasRegion(r.result.name() + "-icon") ?
|
||||
Draw.region(r.result.name() + "-icon") : Draw.region(r.result.name());
|
||||
ImageButton image = new ImageButton(region, "select");
|
||||
|
||||
image.addListener(new ClickListener(){
|
||||
@Override
|
||||
public void enter(InputEvent event, float x, float y, int pointer, Element fromActor) {
|
||||
super.enter(event, x, y, pointer, fromActor);
|
||||
if (hoveredDescriptionRecipe != r) {
|
||||
hoveredDescriptionRecipe = r;
|
||||
updateRecipe(r);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(InputEvent event, float x, float y, int pointer, Element toActor) {
|
||||
super.exit(event, x, y, pointer, toActor);
|
||||
hoveredDescriptionRecipe = null;
|
||||
updateRecipe(input.recipe);
|
||||
}
|
||||
});
|
||||
|
||||
image.clicked(() -> {
|
||||
// note: input.recipe only gets set here during a click.
|
||||
// during a hover only the visual description will be updated.
|
||||
boolean nothingSelectedYet = input.recipe == null;
|
||||
boolean selectedSomethingElse = !nothingSelectedYet && input.recipe != r;
|
||||
boolean shouldMakeSelection = nothingSelectedYet || selectedSomethingElse;
|
||||
if (shouldMakeSelection) {
|
||||
input.recipe = r;
|
||||
hoveredDescriptionRecipe = r;
|
||||
updateRecipe(r);
|
||||
} else {
|
||||
input.recipe = null;
|
||||
hoveredDescriptionRecipe = null;
|
||||
updateRecipe(null);
|
||||
}
|
||||
});
|
||||
|
||||
table.add(image).size(size + 8);
|
||||
image.getImageCell().size(size);
|
||||
|
||||
image.update(() -> {
|
||||
boolean canPlace = !control.tutorial().active() || control.tutorial().canPlace();
|
||||
boolean has = (state.inventory.hasItems(r.requirements)) && canPlace;
|
||||
image.setChecked(input.recipe == r);
|
||||
image.setTouchable(canPlace ? Touchable.enabled : Touchable.disabled);
|
||||
image.getImage().setColor(has ? Color.WHITE : Hue.lightness(0.33f));
|
||||
});
|
||||
|
||||
if (i % rows == rows - 1)
|
||||
table.row();
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
table.setVisible(button::isChecked);
|
||||
|
||||
stack.add(table);
|
||||
}
|
||||
|
||||
|
||||
row();
|
||||
add(stack).colspan(Section.values().length);
|
||||
margin(10f);
|
||||
|
||||
marginLeft(1f);
|
||||
marginRight(1f);
|
||||
|
||||
end();
|
||||
}}.right().bottom().uniformX();
|
||||
|
||||
row();
|
||||
|
||||
if(!mobile) {
|
||||
weapons = new table("button").margin(0).fillX().end().get();
|
||||
}
|
||||
|
||||
visible(() -> !state.is(State.menu) && shown);
|
||||
|
||||
}}.end().get();
|
||||
}}.end();
|
||||
|
||||
updateWeapons();
|
||||
}
|
||||
|
||||
public void updateWeapons(){
|
||||
if(mobile) return;
|
||||
|
||||
weapons.clearChildren();
|
||||
weapons.left();
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
|
||||
for(int i = 0; i < control.upgrades().getWeapons().size; i ++){
|
||||
Weapon weapon = control.upgrades().getWeapons().get(i);
|
||||
weapons.addImageButton(weapon.name, "toggle", 8*3, () -> {
|
||||
player.weaponLeft = player.weaponRight = weapon;
|
||||
}).left().size(40f, 45f).padRight(-1).group(group);
|
||||
}
|
||||
|
||||
int idx = control.upgrades().getWeapons().indexOf(player.weaponLeft, true);
|
||||
|
||||
if(idx != -1)
|
||||
group.getButtons().get(idx).setChecked(true);
|
||||
else if(group.getButtons().size > 0)
|
||||
group.getButtons().get(0).setChecked(true);
|
||||
}
|
||||
|
||||
public void toggle(boolean show, float t, Interpolation ip){
|
||||
if(!show){
|
||||
blocks.actions(Actions.translateBy(0, -blocks.getHeight() - stack.getHeight(), t, ip), Actions.call(() -> shown = false));
|
||||
}else{
|
||||
shown = true;
|
||||
blocks.actions(Actions.translateBy(0, -blocks.getTranslation().y, t, ip));
|
||||
}
|
||||
}
|
||||
|
||||
void updateRecipe(Recipe recipe){
|
||||
if (recipe == null) {
|
||||
desctable.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
desctable.clear();
|
||||
desctable.setTouchable(Touchable.enabled);
|
||||
|
||||
desctable.defaults().left();
|
||||
desctable.left();
|
||||
desctable.margin(12);
|
||||
|
||||
Table header = new Table();
|
||||
|
||||
desctable.add(header).left();
|
||||
|
||||
desctable.row();
|
||||
|
||||
TextureRegion region = Draw.hasRegion(recipe.result.name() + "-icon") ?
|
||||
Draw.region(recipe.result.name() + "-icon") : Draw.region(recipe.result.name());
|
||||
|
||||
header.addImage(region).size(8*5).padTop(4);
|
||||
Label nameLabel = new Label(recipe.result.formalName);
|
||||
nameLabel.setWrap(true);
|
||||
header.add(nameLabel).padLeft(2).width(120f);
|
||||
|
||||
//extra info
|
||||
if(recipe.result.fullDescription != null){
|
||||
header.addButton("?", () -> showBlockInfo(recipe.result)).expandX().padLeft(3).top().right().size(40f, 44f).padTop(-2);
|
||||
}
|
||||
|
||||
desctable.add().pad(2);
|
||||
|
||||
Table requirements = new Table();
|
||||
|
||||
desctable.row();
|
||||
|
||||
desctable.add(requirements);
|
||||
desctable.left();
|
||||
|
||||
for(ItemStack stack : recipe.requirements){
|
||||
requirements.addImage(Draw.region("icon-"+stack.item.name)).size(8*3);
|
||||
Label reqlabel = new Label("");
|
||||
|
||||
reqlabel.update(()->{
|
||||
int current = state.inventory.getAmount(stack.item);
|
||||
String text = Mathf.clamp(current, 0, stack.amount) + "/" + stack.amount;
|
||||
|
||||
reqlabel.setColor(current < stack.amount ? Colors.get("missingitems") : Color.WHITE);
|
||||
|
||||
reqlabel.setText(text);
|
||||
});
|
||||
|
||||
requirements.add(reqlabel).left();
|
||||
requirements.row();
|
||||
}
|
||||
|
||||
desctable.row();
|
||||
|
||||
Label label = new Label("[health]"+ Bundles.get("text.health")+": " + recipe.result.health);
|
||||
label.setWrap(true);
|
||||
desctable.add(label).width(200).padTop(4).padBottom(2);
|
||||
}
|
||||
|
||||
public void showBlockInfo(Block block){
|
||||
statlist.clear();
|
||||
block.getStats(statlist);
|
||||
|
||||
Label desclabel = new Label(block.fullDescription);
|
||||
desclabel.setWrap(true);
|
||||
|
||||
boolean wasPaused = state.is(State.paused);
|
||||
state.set(State.paused);
|
||||
|
||||
FloatingDialog d = new FloatingDialog("$text.blocks.blockinfo");
|
||||
Table table = new Table();
|
||||
table.defaults().pad(1f);
|
||||
ScrollPane pane = new ScrollPane(table, "clear");
|
||||
pane.setFadeScrollBars(false);
|
||||
Table top = new Table();
|
||||
top.left();
|
||||
top.add(new Image(Draw.region(block.name))).size(8*5 * block.width);
|
||||
top.add("[accent]"+block.formalName).padLeft(6f);
|
||||
table.add(top).fill().left();
|
||||
table.row();
|
||||
table.add(desclabel).width(600);
|
||||
table.row();
|
||||
|
||||
d.content().add(pane).grow();
|
||||
|
||||
if(statlist.size > 0){
|
||||
table.add("$text.blocks.extrainfo").padTop(6).padBottom(5).left();
|
||||
table.row();
|
||||
}
|
||||
|
||||
for(String s : statlist){
|
||||
if(s.contains(":")) {
|
||||
String color = s.substring(0, s.indexOf("]")+1);
|
||||
String first = s.substring(color.length(), s.indexOf(":")).replace("/", "").replace(" ", "").toLowerCase();
|
||||
String last = s.substring(s.indexOf(":"), s.length());
|
||||
s = color + Bundles.get("text.blocks." + first) + last;
|
||||
}
|
||||
table.add(s).left();
|
||||
table.row();
|
||||
}
|
||||
|
||||
d.buttons().addButton("$text.ok", ()->{
|
||||
if(!wasPaused) state.set(State.playing);
|
||||
d.hide();
|
||||
}).size(110, 50).pad(10f);
|
||||
|
||||
d.show();
|
||||
}
|
||||
|
||||
public void showBlockLogs(int x, int y){
|
||||
boolean wasPaused = state.is(State.paused);
|
||||
state.set(State.paused);
|
||||
|
||||
FloatingDialog d = new FloatingDialog("$text.blocks.editlogs");
|
||||
Table table = new Table();
|
||||
table.defaults().pad(1f);
|
||||
ScrollPane pane = new ScrollPane(table, "clear");
|
||||
pane.setFadeScrollBars(false);
|
||||
Table top = new Table();
|
||||
top.left();
|
||||
top.add("[accent]Edit logs for: "+ x + ", " + y);
|
||||
table.add(top).fill().left();
|
||||
table.row();
|
||||
|
||||
d.content().add(pane).grow();
|
||||
|
||||
if(currentEditLogs == null || currentEditLogs.size == 0) {
|
||||
table.add("$text.block.editlogsnotfound").left();
|
||||
table.row();
|
||||
}
|
||||
else {
|
||||
for(int i = 0; i < currentEditLogs.size; i++) {
|
||||
EditLog log = currentEditLogs.get(i);
|
||||
table.add("[gold]" + (i + 1) + ". [white]" + log.info()).left();
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
d.buttons().addButton("$text.ok", () -> {
|
||||
if(!wasPaused)
|
||||
state.set(State.playing);
|
||||
d.hide();
|
||||
}).size(110, 50).pad(10f);
|
||||
|
||||
d.show();
|
||||
}
|
||||
|
||||
public void updateItems(){
|
||||
|
||||
itemtable.clear();
|
||||
itemtable.left();
|
||||
|
||||
if(state.mode.infiniteResources){
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < state.inventory.getItems().length; i ++){
|
||||
int amount = state.inventory.getItems()[i];
|
||||
if(amount == 0) continue;
|
||||
String formatted = amount > 99999999 ? "inf" : format(amount);
|
||||
Image image = new Image(Draw.hasRegion("icon-" + Item.getByID(i).name) ?
|
||||
Draw.region("icon-" + Item.getByID(i).name) : Draw.region("blank"));
|
||||
Label label = new Label(formatted);
|
||||
label.setFontScale(fontscale*1.5f);
|
||||
itemtable.add(image).size(8*3);
|
||||
itemtable.add(label).expandX().left();
|
||||
if(i % 2 == 1 && i > 0) itemtable.row();
|
||||
}
|
||||
}
|
||||
|
||||
String format(int number){
|
||||
if(number > 1000000) {
|
||||
return Strings.toFixed(number/1000000f, 1) + "[gray]mil";
|
||||
}else if(number > 10000){
|
||||
return number/1000 + "[gray]k";
|
||||
}else if(number > 1000){
|
||||
return Strings.toFixed(number/1000f, 1) + "[gray]k";
|
||||
}else{
|
||||
return number + "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,31 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Input.TextInput;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.ui.Label;
|
||||
import io.anuke.arc.scene.ui.Label.LabelStyle;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
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.core.Platform;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Inputs;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.ui.Label;
|
||||
import io.anuke.ucore.scene.ui.Label.LabelStyle;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
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.state;
|
||||
import static io.anuke.ucore.core.Core.scene;
|
||||
import static io.anuke.ucore.core.Core.skin;
|
||||
import static io.anuke.arc.Core.input;
|
||||
import static io.anuke.arc.Core.scene;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ChatFragment extends Table implements Fragment{
|
||||
public class ChatFragment extends Table{
|
||||
private final static int messagesShown = 10;
|
||||
private final static int maxLength = 150;
|
||||
private Array<ChatMessage> messages = new Array<>();
|
||||
private float fadetime;
|
||||
private boolean chatOpen = false;
|
||||
@@ -36,42 +34,53 @@ public class ChatFragment extends Table implements Fragment{
|
||||
private BitmapFont font;
|
||||
private GlyphLayout layout = new GlyphLayout();
|
||||
private float offsetx = Unit.dp.scl(4), offsety = Unit.dp.scl(4), fontoffsetx = Unit.dp.scl(2), chatspace = Unit.dp.scl(50);
|
||||
private float textWidth = Unit.dp.scl(600);
|
||||
private Color shadowColor = new Color(0, 0, 0, 0.4f);
|
||||
private float textspacing = Unit.dp.scl(10);
|
||||
private Array<String> history = new Array<String>();
|
||||
private Array<String> history = new Array<>();
|
||||
private int historyPos = 0;
|
||||
private int scrollPos = 0;
|
||||
private Fragment container = new Fragment(){
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
scene.add(ChatFragment.this);
|
||||
}
|
||||
};
|
||||
|
||||
public ChatFragment(){
|
||||
super();
|
||||
|
||||
setFillParent(true);
|
||||
font = Core.skin.getFont("default-font");
|
||||
font = scene.skin.getFont("default-font");
|
||||
|
||||
setVisible(() -> !state.is(State.menu) && Net.active());
|
||||
visible(() -> {
|
||||
if(!Net.active() && messages.size > 0){
|
||||
clearMessages();
|
||||
|
||||
//TODO put it in input?
|
||||
update(() -> {
|
||||
if(!Net.active() && chatOpen){
|
||||
hide();
|
||||
if(chatOpen){
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
if(Net.active() && Inputs.keyTap("chat")){
|
||||
return !state.is(State.menu) && Net.active();
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
|
||||
if(Net.active() && input.keyTap(Binding.chat)){
|
||||
toggle();
|
||||
}
|
||||
|
||||
if (chatOpen) {
|
||||
if (Inputs.keyTap("chat_history_prev") && historyPos < history.size - 1) {
|
||||
if (historyPos == 0) history.set(0, chatfield.getText());
|
||||
if(chatOpen){
|
||||
if(input.keyTap(Binding.chat_history_prev) && historyPos < history.size - 1){
|
||||
if(historyPos == 0) history.set(0, chatfield.getText());
|
||||
historyPos++;
|
||||
updateChat();
|
||||
}
|
||||
if (Inputs.keyTap("chat_history_next") && historyPos > 0) {
|
||||
if(input.keyTap(Binding.chat_history_next) && historyPos > 0){
|
||||
historyPos--;
|
||||
updateChat();
|
||||
}
|
||||
scrollPos = (int)Mathf.clamp(scrollPos + Inputs.getAxis("chat_scroll"), 0, Math.max(0, messages.size - messagesShown));
|
||||
scrollPos = (int)Mathf.clamp(scrollPos + input.axis(Binding.chat_scroll), 0, Math.max(0, messages.size - messagesShown));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,9 +88,8 @@ public class ChatFragment extends Table implements Fragment{
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
scene.add(this);
|
||||
public Fragment container(){
|
||||
return container;
|
||||
}
|
||||
|
||||
public void clearMessages(){
|
||||
@@ -95,70 +103,72 @@ public class ChatFragment extends Table implements Fragment{
|
||||
fieldlabel.getStyle().font = font;
|
||||
fieldlabel.setStyle(fieldlabel.getStyle());
|
||||
|
||||
chatfield = new TextField("", new TextField.TextFieldStyle(skin.get(TextField.TextFieldStyle.class)));
|
||||
chatfield.setTextFieldFilter((field, c) -> field.getText().length() < maxLength);
|
||||
chatfield = new TextField("", new TextField.TextFieldStyle(scene.skin.get(TextField.TextFieldStyle.class)));
|
||||
chatfield.setFilter((field, c) -> field.getText().length() < Vars.maxTextLength);
|
||||
chatfield.getStyle().background = null;
|
||||
chatfield.getStyle().font = scene.skin.getFont("default-font-chat");
|
||||
chatfield.getStyle().fontColor = Color.WHITE;
|
||||
chatfield.getStyle().font = skin.getFont("default-font-chat");
|
||||
chatfield.setStyle(chatfield.getStyle());
|
||||
Platform.instance.addDialog(chatfield, maxLength);
|
||||
|
||||
bottom().left().marginBottom(offsety).marginLeft(offsetx*2).add(fieldlabel).padBottom(4f);
|
||||
bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(6f);
|
||||
|
||||
add(chatfield).padBottom(offsety).padLeft(offsetx).growX().padRight(offsetx).height(28);
|
||||
|
||||
if(Vars.mobile) {
|
||||
if(Vars.mobile){
|
||||
marginBottom(105f);
|
||||
marginRight(240f);
|
||||
}
|
||||
|
||||
if(Vars.mobile) {
|
||||
addImageButton("icon-arrow-right", 14 * 2, this::toggle).size(46f, 51f).visible(() -> chatOpen).pad(2f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float alpha){
|
||||
public void draw(){
|
||||
float opacity = Core.settings.getInt("chatopacity") / 100f;
|
||||
float textWidth = Math.min(Core.graphics.getWidth()/1.5f, Unit.dp.scl(700f));
|
||||
|
||||
batch.setColor(shadowColor);
|
||||
Draw.color(shadowColor);
|
||||
|
||||
if(chatOpen)
|
||||
batch.draw(skin.getRegion("white"), offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight()-1);
|
||||
if(chatOpen){
|
||||
Fill.crect(offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight() - 1);
|
||||
}
|
||||
|
||||
super.draw(batch, alpha);
|
||||
super.draw();
|
||||
|
||||
float spacing = chatspace;
|
||||
|
||||
chatfield.setVisible(chatOpen);
|
||||
fieldlabel.setVisible(chatOpen);
|
||||
chatfield.visible(chatOpen);
|
||||
fieldlabel.visible(chatOpen);
|
||||
|
||||
batch.setColor(shadowColor);
|
||||
Draw.color(shadowColor);
|
||||
Draw.alpha(shadowColor.a * opacity);
|
||||
|
||||
float theight = offsety + spacing + getMarginBottom();
|
||||
for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || chatOpen); i++){
|
||||
|
||||
layout.setText(font, messages.get(i).formattedMessage, Color.WHITE, textWidth, Align.bottomLeft, true);
|
||||
theight += layout.height+textspacing;
|
||||
if(i - scrollPos == 0) theight -= textspacing+1;
|
||||
theight += layout.height + textspacing;
|
||||
if(i - scrollPos == 0) theight -= textspacing + 1;
|
||||
|
||||
font.getCache().clear();
|
||||
font.getCache().addText(messages.get(i).formattedMessage, fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true);
|
||||
|
||||
if(!chatOpen && fadetime-i < 1f && fadetime-i >= 0f){
|
||||
font.getCache().setAlphas(fadetime-i);
|
||||
batch.setColor(0, 0, 0, shadowColor.a*(fadetime-i));
|
||||
if(!chatOpen && fadetime - i < 1f && fadetime - i >= 0f){
|
||||
font.getCache().setAlphas((fadetime - i) * opacity);
|
||||
Draw.color(0, 0, 0, shadowColor.a * (fadetime - i) * opacity);
|
||||
}else{
|
||||
font.getCache().setAlphas(opacity);
|
||||
}
|
||||
|
||||
batch.draw(skin.getRegion("white"), offsetx, theight-layout.height-2, textWidth + Unit.dp.scl(4f), layout.height+textspacing);
|
||||
batch.setColor(shadowColor);
|
||||
Fill.crect(offsetx, theight - layout.height - 2, textWidth + Unit.dp.scl(4f), layout.height + textspacing);
|
||||
Draw.color(shadowColor);
|
||||
Draw.alpha(opacity * shadowColor.a);
|
||||
|
||||
font.getCache().draw(batch);
|
||||
font.getCache().draw();
|
||||
}
|
||||
|
||||
batch.setColor(Color.WHITE);
|
||||
Draw.color();
|
||||
|
||||
if(fadetime > 0 && !chatOpen)
|
||||
fadetime -= Timers.delta()/180f;
|
||||
fadetime -= Time.delta() / 180f;
|
||||
}
|
||||
|
||||
private void sendMessage(){
|
||||
@@ -168,15 +178,29 @@ public class ChatFragment extends Table implements Fragment{
|
||||
if(message.replaceAll(" ", "").isEmpty()) return;
|
||||
|
||||
history.insert(1, message);
|
||||
NetEvents.handleSendMessage(message);
|
||||
|
||||
Call.sendChatMessage(message);
|
||||
}
|
||||
|
||||
public void toggle(){
|
||||
|
||||
if(!chatOpen){
|
||||
scene.setKeyboardFocus(chatfield);
|
||||
chatfield.fireClick();
|
||||
chatOpen = !chatOpen;
|
||||
if(mobile){
|
||||
TextInput input = new TextInput();
|
||||
input.maxLength = maxTextLength;
|
||||
input.accepted = text -> {
|
||||
chatfield.setText(text);
|
||||
sendMessage();
|
||||
hide();
|
||||
Core.input.setOnscreenKeyboardVisible(false);
|
||||
};
|
||||
input.canceled = this::hide;
|
||||
Core.input.getTextInput(input);
|
||||
}else{
|
||||
chatfield.fireClick();
|
||||
}
|
||||
}else{
|
||||
scene.setKeyboardFocus(null);
|
||||
chatOpen = !chatOpen;
|
||||
@@ -191,12 +215,12 @@ public class ChatFragment extends Table implements Fragment{
|
||||
clearChatInput();
|
||||
}
|
||||
|
||||
public void updateChat() {
|
||||
public void updateChat(){
|
||||
chatfield.setText(history.get(historyPos));
|
||||
chatfield.setCursorPosition(chatfield.getText().length());
|
||||
}
|
||||
|
||||
public void clearChatInput() {
|
||||
public void clearChatInput(){
|
||||
historyPos = 0;
|
||||
history.set(0, "");
|
||||
chatfield.setText("");
|
||||
@@ -228,7 +252,7 @@ public class ChatFragment extends Table implements Fragment{
|
||||
if(sender == null){ //no sender, this is a server message?
|
||||
formattedMessage = message;
|
||||
}else{
|
||||
formattedMessage = "[CORAL][["+sender+"[CORAL]]:[WHITE] "+message;
|
||||
formattedMessage = "[CORAL][[" + sender + "[CORAL]]:[WHITE] " + message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.enemies.Enemy;
|
||||
import io.anuke.mindustry.entities.enemies.EnemyTypes;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.builders.button;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.ui.Label;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Log.LogHandler;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class DebugFragment implements Fragment {
|
||||
private static StringBuilder log = new StringBuilder();
|
||||
|
||||
static{
|
||||
Log.setLogger(new LogHandler(){
|
||||
@Override
|
||||
public void print(String text, Object... args){
|
||||
super.print(text, args);
|
||||
if(log.length() < 1000) {
|
||||
log.append(Log.format(text, args));
|
||||
log.append("\n");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(){
|
||||
new table(){{
|
||||
visible(() -> debug);
|
||||
|
||||
atop().aright();
|
||||
|
||||
new table("pane"){{
|
||||
defaults().fillX();
|
||||
|
||||
new label("Debug");
|
||||
row();
|
||||
new button("noclip", "toggle", () -> noclip = !noclip);
|
||||
row();
|
||||
new button("hideplayer", "toggle", () -> showPlayer = !showPlayer);
|
||||
row();
|
||||
new button("blocks", "toggle", () -> showBlockDebug = !showBlockDebug);
|
||||
row();
|
||||
new button("paths", "toggle", () -> showPaths = !showPaths);
|
||||
row();
|
||||
new button("wave", () -> state.wavetime = 0f);
|
||||
row();
|
||||
new button("time 0", () -> Timers.resetTime(0f));
|
||||
row();
|
||||
new button("time max", () -> Timers.resetTime(1080000 - 60*10));
|
||||
row();
|
||||
new button("clear", () -> {
|
||||
enemyGroup.clear();
|
||||
state.enemies = 0;
|
||||
netClient.clearRecieved();
|
||||
});
|
||||
row();
|
||||
new button("spawn", () -> {
|
||||
new Enemy(EnemyTypes.healer).set(player.x, player.y).add();
|
||||
});
|
||||
row();
|
||||
}}.end();
|
||||
|
||||
row();
|
||||
|
||||
}}.end();
|
||||
|
||||
|
||||
new table(){{
|
||||
visible(() -> console);
|
||||
|
||||
atop().aleft();
|
||||
|
||||
new table("pane") {{
|
||||
defaults().fillX();
|
||||
|
||||
ScrollPane pane = new ScrollPane(new Label(DebugFragment::debugInfo), "clear");
|
||||
|
||||
add(pane);
|
||||
row();
|
||||
new button("dump", () -> {
|
||||
try{
|
||||
FileHandle file = Gdx.files.local("packet-dump.txt");
|
||||
file.writeString("--INFO--\n", false);
|
||||
file.writeString(debugInfo(), true);
|
||||
file.writeString("--LOG--\n\n", true);
|
||||
file.writeString(log.toString(), true);
|
||||
}catch (Exception e){
|
||||
ui.showError("Error dumping log.");
|
||||
}
|
||||
});
|
||||
}}.end();
|
||||
}}.end();
|
||||
|
||||
new table(){{
|
||||
visible(() -> console);
|
||||
|
||||
atop();
|
||||
|
||||
Table table = new Table("pane");
|
||||
table.label(() -> log.toString());
|
||||
|
||||
ScrollPane pane = new ScrollPane(table, "clear");
|
||||
|
||||
get().add(pane);
|
||||
}}.end();
|
||||
}
|
||||
|
||||
public static void printDebugInfo(){
|
||||
Gdx.app.error("Minudstry Info Dump", debugInfo());
|
||||
}
|
||||
|
||||
public static String debugInfo(){
|
||||
StringBuilder result = join(
|
||||
"net.active: " + Net.active(),
|
||||
"net.server: " + Net.server(),
|
||||
"net.client: " + Net.client(),
|
||||
"state: " + state.getState(),
|
||||
Net.client() ?
|
||||
"chat.open: " + ui.chatfrag.chatOpen() + "\n" +
|
||||
"chat.messages: " + ui.chatfrag.getMessagesSize() + "\n" +
|
||||
"client.connecting: " + netClient.isConnecting() + "\n" : "",
|
||||
"players: " + playerGroup.size(),
|
||||
"enemies: " + enemyGroup.size(),
|
||||
"tiles: " + tileGroup.size(),
|
||||
"time: " + Timers.time(),
|
||||
world.getCore() != null && world.getCore().entity != null ? "core.health: " + world.getCore().entity.health : "",
|
||||
"core: " + world.getCore(),
|
||||
"state.gameover: " + state.gameOver,
|
||||
"state: " + state.getState(),
|
||||
!Net.server() ? clientDebug.getOut() : serverDebug.getOut()
|
||||
);
|
||||
|
||||
result.append("players: ");
|
||||
|
||||
for(Player player : playerGroup.all()){
|
||||
result.append(" name: ");
|
||||
result.append(player.name);
|
||||
result.append("\n");
|
||||
result.append(" id: ");
|
||||
result.append(player.id);
|
||||
result.append("\n");
|
||||
result.append(" cid: ");
|
||||
result.append(player.clientid);
|
||||
result.append("\n");
|
||||
result.append(" dead: ");
|
||||
result.append(player.isDead());
|
||||
result.append("\n");
|
||||
result.append(" pos: ");
|
||||
result.append(player.x);
|
||||
result.append(", ");
|
||||
result.append(player.y);
|
||||
result.append("\n");
|
||||
result.append(" android: ");
|
||||
result.append(player.isAndroid);
|
||||
result.append("\n");
|
||||
result.append(" local: ");
|
||||
result.append(player.isLocal);
|
||||
result.append("\n");
|
||||
|
||||
result.append("\n");
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static StringBuilder join(String... strings){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String string : strings) {
|
||||
builder.append(string);
|
||||
builder.append("\n");
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
public interface Fragment{
|
||||
public void build();
|
||||
import io.anuke.arc.scene.Group;
|
||||
|
||||
public abstract class Fragment{
|
||||
public abstract void build(Group parent);
|
||||
}
|
||||
|
||||
@@ -1,243 +1,624 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.scene.Element;
|
||||
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.style.TextureRegionDrawable;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.scene.utils.Elements;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Inputs;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.scene.actions.Actions;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.scene.ui.Label;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.mindustry.net.Packets.AdminAction;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.UnitType;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class HudFragment implements Fragment{
|
||||
public final BlocksFragment blockfrag = new BlocksFragment();
|
||||
public class HudFragment extends Fragment{
|
||||
public final PlacementFragment blockfrag = new PlacementFragment();
|
||||
|
||||
private ImageButton menu, flip;
|
||||
private Table respawntable;
|
||||
private Table wavetable;
|
||||
private Label infolabel;
|
||||
private boolean shown = true;
|
||||
private float dsize = 58;
|
||||
private float isize = 40;
|
||||
private ImageButton flip;
|
||||
private Table lastUnlockTable;
|
||||
private Table lastUnlockLayout;
|
||||
private boolean shown = true;
|
||||
private float dsize = 59;
|
||||
|
||||
public void build(){
|
||||
private float coreAttackTime;
|
||||
private float lastCoreHP;
|
||||
private Team lastTeam;
|
||||
private float coreAttackOpacity = 0f;
|
||||
|
||||
//menu at top left
|
||||
new table(){{
|
||||
atop();
|
||||
aleft();
|
||||
public void build(Group parent){
|
||||
|
||||
new table(){{
|
||||
//menu at top left
|
||||
parent.fill(cont -> {
|
||||
cont.top().left().visible(() -> !state.is(State.menu));
|
||||
|
||||
new table() {{
|
||||
left();
|
||||
defaults().size(dsize).left();
|
||||
if(mobile){
|
||||
|
||||
menu = new imagebutton("icon-menu", isize, ui.paused::show).get();
|
||||
flip = new imagebutton("icon-arrow-up", isize, () -> toggleMenus()).get();
|
||||
{
|
||||
Table select = new Table();
|
||||
|
||||
update(t -> {
|
||||
if(Inputs.keyTap("toggle_menus") && !ui.chatfrag.chatOpen()){
|
||||
toggleMenus();
|
||||
}
|
||||
});
|
||||
select.visible(() -> !state.is(State.menu));
|
||||
select.left();
|
||||
select.defaults().size(dsize).left();
|
||||
|
||||
new imagebutton("icon-pause", isize, () -> {
|
||||
if (Net.active()) {
|
||||
ui.listfrag.visible = !ui.listfrag.visible;
|
||||
} else {
|
||||
state.set(state.is(State.paused) ? State.playing : State.paused);
|
||||
}
|
||||
}).update(i -> {
|
||||
if (Net.active()) {
|
||||
i.getStyle().imageUp = Core.skin.getDrawable("icon-players");
|
||||
} else {
|
||||
i.setDisabled(Net.active());
|
||||
i.getStyle().imageUp = Core.skin.getDrawable(state.is(State.paused) ? "icon-play" : "icon-pause");
|
||||
}
|
||||
}).get();
|
||||
select.addImageButton("icon-menu-large", "clear", iconsize, ui.paused::show);
|
||||
flip = select.addImageButton("icon-arrow-up", "clear", iconsize, this::toggleMenus).get();
|
||||
|
||||
new imagebutton("icon-settings", isize, () -> {
|
||||
if (Net.active() && mobile) {
|
||||
if (ui.chatfrag.chatOpen()) {
|
||||
ui.chatfrag.hide();
|
||||
} else {
|
||||
ui.chatfrag.toggle();
|
||||
}
|
||||
} else {
|
||||
ui.settings.show();
|
||||
}
|
||||
}).update(i -> {
|
||||
if (Net.active() && mobile) {
|
||||
i.getStyle().imageUp = Core.skin.getDrawable("icon-chat");
|
||||
} else {
|
||||
i.getStyle().imageUp = Core.skin.getDrawable("icon-settings");
|
||||
}
|
||||
}).get();
|
||||
select.addImageButton("icon-pause", "clear", iconsize, () -> {
|
||||
if(Net.active()){
|
||||
ui.listfrag.toggle();
|
||||
}else{
|
||||
state.set(state.is(State.paused) ? State.playing : State.paused);
|
||||
}
|
||||
}).update(i -> {
|
||||
if(Net.active()){
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-players");
|
||||
}else{
|
||||
i.setDisabled(false);
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable(state.is(State.paused) ? "icon-play" : "icon-pause");
|
||||
}
|
||||
}).get();
|
||||
|
||||
}}.end();
|
||||
select.addImageButton("icon-settings", "clear", iconsize, () -> {
|
||||
if(Net.active() && mobile){
|
||||
if(ui.chatfrag.chatOpen()){
|
||||
ui.chatfrag.hide();
|
||||
}else{
|
||||
ui.chatfrag.toggle();
|
||||
}
|
||||
}else if(world.isZone()){
|
||||
ui.tech.show();
|
||||
}else{
|
||||
ui.database.show();
|
||||
}
|
||||
}).update(i -> {
|
||||
if(Net.active() && mobile){
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-chat");
|
||||
}else{
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-database");
|
||||
}
|
||||
}).get();
|
||||
|
||||
row();
|
||||
select.addImage("blank").color(Pal.accent).width(3f).fillY();
|
||||
|
||||
new table() {{
|
||||
touchable(Touchable.enabled);
|
||||
visible(() -> shown);
|
||||
addWaveTable();
|
||||
}}.fillX().end();
|
||||
float size = Unit.dp.scl(dsize);
|
||||
Array<Element> children = new Array<>(select.getChildren());
|
||||
|
||||
row();
|
||||
//now, you may be wondering, why is this necessary? the answer is, I don't know, but it fixes layout issues somehow
|
||||
int index = 0;
|
||||
for(Element elem : children){
|
||||
int fi = index++;
|
||||
Core.scene.add(elem);
|
||||
elem.visible(() -> {
|
||||
if(fi < 4){
|
||||
elem.setSize(size);
|
||||
}else{
|
||||
elem.setSize(Unit.dp.scl(3f), size);
|
||||
}
|
||||
elem.setPosition(fi * size, Core.graphics.getHeight(), Align.topLeft);
|
||||
return !state.is(State.menu);
|
||||
});
|
||||
}
|
||||
|
||||
visible(() -> !state.is(State.menu));
|
||||
cont.add().size(dsize * 4 + 3, dsize).left();
|
||||
}
|
||||
|
||||
infolabel = new Label(() -> (Settings.getBool("fps") ? (Gdx.graphics.getFramesPerSecond() + " FPS") +
|
||||
(threads.isEnabled() ? " / " + threads.getFPS() + " TPS" : "") + (Net.client() && !gwt ? "\nPing: " + Net.getPing() : "") : ""));
|
||||
row();
|
||||
add(infolabel).size(-1);
|
||||
cont.row();
|
||||
cont.addImage("blank").height(3f).color(Pal.accent).fillX();
|
||||
cont.row();
|
||||
}
|
||||
|
||||
}}.end();
|
||||
cont.update(() -> {
|
||||
if(!Core.input.keyDown(Binding.gridMode) && Core.input.keyTap(Binding.toggle_menus) && !ui.chatfrag.chatOpen() && !Core.scene.hasDialog() && !(Core.scene.getKeyboardFocus() instanceof TextField)){
|
||||
toggleMenus();
|
||||
}
|
||||
});
|
||||
|
||||
Table wavesMain, editorMain;
|
||||
boolean[] prev = {false};
|
||||
|
||||
cont.stack(wavesMain = new Table(), editorMain = new Table()).height(wavesMain.getPrefHeight()).update(s -> {
|
||||
((Table)s.getParent()).getCell(s).height((wavesMain.isVisible() ? wavesMain.getPrefHeight() : editorMain.getPrefHeight()) / Unit.dp.scl(1f));
|
||||
if(prev[0] != wavesMain.isVisible()){
|
||||
s.getParent().pack();
|
||||
prev[0] = wavesMain.isVisible();
|
||||
}
|
||||
});
|
||||
|
||||
}}.end();
|
||||
{
|
||||
wavesMain.visible(() -> shown && !state.isEditor());
|
||||
wavesMain.left();
|
||||
Stack stack = new Stack();
|
||||
TextButton waves = new TextButton("", "wave");
|
||||
Table btable = new Table().margin(0);
|
||||
|
||||
//tutorial ui table
|
||||
new table(){{
|
||||
control.tutorial().buildUI(this);
|
||||
stack.add(waves);
|
||||
stack.add(btable);
|
||||
|
||||
visible(() -> control.tutorial().active());
|
||||
}}.end();
|
||||
addWaveTable(waves);
|
||||
addPlayButton(btable);
|
||||
wavesMain.add(stack).width(dsize * 4 + 3f);
|
||||
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();
|
||||
wavesMain.row();
|
||||
}
|
||||
|
||||
//paused table
|
||||
new table(){{
|
||||
visible(() -> state.is(State.paused) && !Net.active());
|
||||
atop();
|
||||
{
|
||||
editorMain.table("button-edge-4", t -> {
|
||||
//t.margin(0f);
|
||||
t.add("$editor.teams").growX().left();
|
||||
t.row();
|
||||
t.table(teams -> {
|
||||
teams.left();
|
||||
int i = 0;
|
||||
for(Team team : Team.all){
|
||||
ImageButton button = teams.addImageButton("white", "clear-toggle-partial", 40f, () -> Call.setPlayerTeamEditor(player, team))
|
||||
.size(50f).margin(6f).get();
|
||||
button.getImageCell().grow();
|
||||
button.getStyle().imageUpColor = team.color;
|
||||
button.update(() -> button.setChecked(player.getTeam() == team));
|
||||
|
||||
new table("pane"){{
|
||||
new label("[orange]< "+ Bundles.get("text.paused") + " >").scale(0.75f).pad(6);
|
||||
}}.end();
|
||||
}}.end();
|
||||
if(++i % 3 == 0){
|
||||
teams.row();
|
||||
}
|
||||
}
|
||||
}).left();
|
||||
|
||||
//respawn background table
|
||||
new table("white"){{
|
||||
respawntable = get();
|
||||
respawntable.setColor(Color.CLEAR);
|
||||
update(t -> {
|
||||
if(state.is(State.menu)){
|
||||
respawntable.setColor(Color.CLEAR);
|
||||
}
|
||||
});
|
||||
}}.end();
|
||||
if(enableUnitEditing){
|
||||
|
||||
//respawn table
|
||||
new table(){{
|
||||
new table("pane"){{
|
||||
t.row();
|
||||
t.addImageTextButton("$editor.spawn", "icon-add", iconsize, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("$editor.spawn");
|
||||
int i = 0;
|
||||
for(UnitType type : content.<UnitType>getBy(ContentType.unit)){
|
||||
dialog.cont.addImageButton("white", 48, () -> {
|
||||
Call.spawnUnitEditor(player, type);
|
||||
dialog.hide();
|
||||
}).get().getStyle().imageUp = new TextureRegionDrawable(type.iconRegion);
|
||||
if(++i % 4 == 0) dialog.cont.row();
|
||||
}
|
||||
dialog.addCloseButton();
|
||||
dialog.setFillParent(false);
|
||||
dialog.show();
|
||||
}).fillX();
|
||||
|
||||
new label(()->"[orange]"+Bundles.get("text.respawn")+" " + (int)(control.getRespawnTime()/60)).scale(0.75f).pad(10);
|
||||
float[] size = {0};
|
||||
float[] position = {0, 0};
|
||||
|
||||
visible(()->control.getRespawnTime() > 0 && !state.is(State.menu));
|
||||
t.row();
|
||||
t.addImageTextButton("$editor.removeunit", "icon-quit", "toggle", iconsize, () -> {
|
||||
|
||||
}}.end();
|
||||
}}.end();
|
||||
}).fillX().update(b -> {
|
||||
boolean[] found = {false};
|
||||
if(b.isChecked()){
|
||||
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(e == null){
|
||||
Vector2 world = Core.input.mouseWorld();
|
||||
Units.nearby(world.x, world.y, 1f, 1f, unit -> {
|
||||
if(!found[0] && unit instanceof BaseUnit){
|
||||
if(Core.input.keyTap(KeyCode.MOUSE_LEFT)){
|
||||
Call.removeUnitEditor(player, (BaseUnit)unit);
|
||||
}
|
||||
found[0] = true;
|
||||
unit.hitbox(Tmp.r1);
|
||||
size[0] = Mathf.lerpDelta(size[0], Tmp.r1.width * 2f + Mathf.absin(Time.time(), 10f, 5f), 0.1f);
|
||||
position[0] = unit.x;
|
||||
position[1] = unit.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
new table(){{
|
||||
abottom();
|
||||
visible(() -> !state.is(State.menu) && control.getSaves().isSaving());
|
||||
Draw.color(Pal.accent, Color.WHITE, Mathf.absin(Time.time(), 8f, 1f));
|
||||
Lines.poly(position[0], position[1], 4, size[0] / 2f);
|
||||
Draw.reset();
|
||||
|
||||
new label("$text.saveload");
|
||||
if(!found[0]){
|
||||
size[0] = Mathf.lerpDelta(size[0], 0f, 0.2f);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).width(dsize * 4 + 3f);
|
||||
editorMain.visible(() -> shown && state.isEditor());
|
||||
}
|
||||
|
||||
}}.end();
|
||||
//fps display
|
||||
cont.table(info -> {
|
||||
info.top().left().margin(4).visible(() -> Core.settings.getBool("fps"));
|
||||
info.update(() -> info.setTranslation(state.rules.waves || state.isEditor() ? 0f : -Unit.dp.scl(dsize * 4 + 3), 0));
|
||||
IntFormat fps = new IntFormat("fps");
|
||||
IntFormat ping = new IntFormat("ping");
|
||||
|
||||
blockfrag.build();
|
||||
}
|
||||
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left();
|
||||
info.row();
|
||||
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left();
|
||||
}).top().left();
|
||||
});
|
||||
|
||||
private void toggleMenus(){
|
||||
if (wavetable.getActions().size != 0) return;
|
||||
//minimap
|
||||
parent.fill(t -> t.top().right().add(new Minimap()).visible(() -> !state.is(State.menu) && Core.settings.getBool("minimap")));
|
||||
|
||||
float dur = 0.3f;
|
||||
Interpolation in = Interpolation.pow3Out;
|
||||
//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))
|
||||
.margin(6).update(u -> u.color.a = Mathf.lerpDelta(u.color.a, Mathf.num(world.spawner.playerNear()), 0.1f)).get().color.a = 0f;
|
||||
});
|
||||
|
||||
flip.getStyle().imageUp = Core.skin.getDrawable(shown ? "icon-arrow-down" : "icon-arrow-up");
|
||||
parent.fill(t -> {
|
||||
t.visible(() -> netServer.isWaitingForPlayers() && !state.is(State.menu));
|
||||
t.table("button", c -> c.add("$waiting.players"));
|
||||
});
|
||||
|
||||
if (shown) {
|
||||
blockfrag.toggle(false, dur, in);
|
||||
wavetable.actions(Actions.translateBy(0, wavetable.getHeight() + dsize, dur, in), Actions.call(() -> shown = false));
|
||||
infolabel.actions(Actions.translateBy(0, wavetable.getHeight(), dur, in), Actions.call(() -> shown = false));
|
||||
} else {
|
||||
shown = true;
|
||||
blockfrag.toggle(true, dur, in);
|
||||
wavetable.actions(Actions.translateBy(0, -wavetable.getTranslation().y, dur, in));
|
||||
infolabel.actions(Actions.translateBy(0, -infolabel.getTranslation().y, dur, in));
|
||||
}
|
||||
}
|
||||
//'core is under attack' table
|
||||
parent.fill(t -> {
|
||||
t.touchable(Touchable.disabled);
|
||||
float notifDuration = 240f;
|
||||
|
||||
private String getEnemiesRemaining() {
|
||||
if(state.enemies == 1) {
|
||||
return Bundles.format("text.enemies.single", state.enemies);
|
||||
} else return Bundles.format("text.enemies", state.enemies);
|
||||
}
|
||||
Events.on(StateChangeEvent.class, event -> {
|
||||
if(event.to == State.menu || event.from == State.menu){
|
||||
coreAttackTime = 0f;
|
||||
lastCoreHP = Float.NaN;
|
||||
}
|
||||
});
|
||||
|
||||
private void addWaveTable(){
|
||||
float uheight = 66f;
|
||||
t.top().visible(() -> {
|
||||
if(state.is(State.menu) || state.teams.get(player.getTeam()).cores.size == 0 || state.teams.get(player.getTeam()).cores.first().entity == null){
|
||||
coreAttackTime = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
wavetable = new table("button"){{
|
||||
aleft();
|
||||
new table(){{
|
||||
aleft();
|
||||
float curr = state.teams.get(player.getTeam()).cores.first().entity.health;
|
||||
|
||||
new label(() -> Bundles.format("text.wave", state.wave)).scale(fontscale*1.5f).left().padLeft(-6);
|
||||
if(lastTeam != player.getTeam()){
|
||||
lastCoreHP = curr;
|
||||
lastTeam = player.getTeam();
|
||||
return false;
|
||||
}
|
||||
|
||||
row();
|
||||
if(!Float.isNaN(lastCoreHP) && curr < lastCoreHP){
|
||||
coreAttackTime = notifDuration;
|
||||
}
|
||||
lastCoreHP = curr;
|
||||
|
||||
new label(()-> state.enemies > 0 ?
|
||||
getEnemiesRemaining() :
|
||||
(control.tutorial().active() || state.mode.disableWaveTimer) ? "$text.waiting"
|
||||
: Bundles.format("text.wave.waiting", (int) (state.wavetime / 60f)))
|
||||
.minWidth(126).padLeft(-6).left();
|
||||
t.getColor().a = coreAttackOpacity;
|
||||
if(coreAttackTime > 0){
|
||||
coreAttackOpacity = Mathf.lerpDelta(coreAttackOpacity, 1f, 0.1f);
|
||||
}else{
|
||||
coreAttackOpacity = Mathf.lerpDelta(coreAttackOpacity, 0f, 0.1f);
|
||||
}
|
||||
|
||||
margin(10f);
|
||||
get().marginLeft(6);
|
||||
}}.left().end();
|
||||
coreAttackTime -= Time.delta();
|
||||
lastTeam = player.getTeam();
|
||||
|
||||
add().growX();
|
||||
return coreAttackOpacity > 0;
|
||||
});
|
||||
t.table("button", top -> top.add("$coreattack").pad(2)
|
||||
.update(label -> label.getColor().set(Color.ORANGE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
|
||||
});
|
||||
|
||||
playButton(uheight);
|
||||
}}.height(uheight).fillX().expandX().end().get();
|
||||
wavetable.getParent().getParent().swapActor(wavetable.getParent(), menu.getParent());
|
||||
}
|
||||
//launch button
|
||||
parent.fill(t -> {
|
||||
t.top().right().visible(() -> !state.is(State.menu));
|
||||
TextButton[] testb = {null};
|
||||
TextButton button = Elements.newButton("$launch", () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("$launch");
|
||||
dialog.update(() -> {
|
||||
if(!testb[0].isVisible()){
|
||||
dialog.hide();
|
||||
}
|
||||
});
|
||||
dialog.cont.add("$launch.confirm").width(500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.buttons.defaults().size(200f, 54f).pad(2f);
|
||||
dialog.setFillParent(false);
|
||||
dialog.buttons.addButton("$cancel", dialog::hide);
|
||||
dialog.buttons.addButton("$ok", () -> {
|
||||
dialog.hide();
|
||||
Call.launchZone();
|
||||
});
|
||||
dialog.keyDown(KeyCode.ESCAPE, dialog::hide);
|
||||
dialog.keyDown(KeyCode.BACK, dialog::hide);
|
||||
dialog.show();
|
||||
|
||||
private void playButton(float uheight){
|
||||
new imagebutton("icon-play", 30f, () -> {
|
||||
state.wavetime = 0f;
|
||||
}).height(uheight).fillX().right().padTop(-8f).padBottom(-12f).padLeft(-15).padRight(-10).width(40f).update(l->{
|
||||
boolean vis = state.enemies <= 0 && (Net.server() || !Net.active());
|
||||
boolean paused = state.is(State.paused) || !vis;
|
||||
|
||||
l.setVisible(vis);
|
||||
l.getStyle().imageUp = Core.skin.getDrawable(vis ? "icon-play" : "clear");
|
||||
l.setTouchable(!paused ? Touchable.enabled : Touchable.disabled);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
public void updateItems(){
|
||||
blockfrag.updateItems();
|
||||
}
|
||||
testb[0] = button;
|
||||
|
||||
public void updateWeapons(){
|
||||
blockfrag.updateWeapons();
|
||||
}
|
||||
|
||||
public void fadeRespawn(boolean in){
|
||||
respawntable.addAction(Actions.color(in ? new Color(0, 0, 0, 0.3f) : Color.CLEAR, 0.3f));
|
||||
}
|
||||
button.getStyle().disabledFontColor = Color.WHITE;
|
||||
button.margin(16f);
|
||||
button.visible(() ->
|
||||
world.isZone() &&
|
||||
world.getZone().metCondition() &&
|
||||
!Net.client() &&
|
||||
state.wave % world.getZone().launchPeriod == 0 && !world.spawner.isSpawning());
|
||||
|
||||
button.update(() -> {
|
||||
if(world.getZone() == null){
|
||||
button.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
button.setText(state.enemies() > 0 ? Core.bundle.format("launch.unable", state.enemies()) : Core.bundle.get("launch") + "\n" +
|
||||
Core.bundle.format("launch.next", state.wave + world.getZone().launchPeriod));
|
||||
|
||||
button.getLabel().setColor(Tmp.c1.set(Color.WHITE).lerp(state.enemies() > 0 ? Color.WHITE : Color.SCARLET,
|
||||
Mathf.absin(Time.time(), 2f, 1f)));
|
||||
});
|
||||
|
||||
button.setDisabled(() -> state.enemies() > 0);
|
||||
button.getLabelCell().left().get().setAlignment(Align.left, Align.left);
|
||||
t.add(button).size(250f, 80f);
|
||||
});
|
||||
|
||||
//paused table
|
||||
parent.fill(t -> {
|
||||
t.top().visible(() -> state.isPaused());
|
||||
t.table("button", top -> top.add("$paused").pad(6f));
|
||||
});
|
||||
|
||||
//'saving' indicator
|
||||
parent.fill(t -> {
|
||||
t.bottom().visible(() -> !state.is(State.menu) && control.saves.isSaving());
|
||||
t.add("$saveload");
|
||||
});
|
||||
|
||||
blockfrag.build(Core.scene.root);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, forward = true, called = Loc.both)
|
||||
public static void setPlayerTeamEditor(Player player, Team team){
|
||||
if(state.isEditor()){
|
||||
player.setTeam(team);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server)
|
||||
public static void spawnUnitEditor(Player player, UnitType type){
|
||||
if(state.isEditor()){
|
||||
BaseUnit unit = type.create(player.getTeam());
|
||||
unit.set(player.x, player.y);
|
||||
unit.rotation = player.rotation;
|
||||
unit.add();
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void removeUnitEditor(Player player, BaseUnit unit){
|
||||
if(state.isEditor() && unit != null){
|
||||
unit.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void showToast(String text){
|
||||
Table table = new Table("button");
|
||||
table.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
table.remove();
|
||||
}
|
||||
});
|
||||
table.margin(12);
|
||||
table.addImage("icon-check").size(iconsize).pad(3);
|
||||
table.add(text).wrap().width(280f).get().setAlignment(Align.center, Align.center);
|
||||
table.pack();
|
||||
|
||||
//create container table which will align and move
|
||||
Table container = Core.scene.table();
|
||||
container.top().add(table);
|
||||
container.setTranslation(0, table.getPrefHeight());
|
||||
container.actions(Actions.translateBy(0, -table.getPrefHeight(), 1f, Interpolation.fade), Actions.delay(4f),
|
||||
//nesting actions() calls is necessary so the right prefHeight() is used
|
||||
Actions.run(() -> container.actions(Actions.translateBy(0, table.getPrefHeight(), 1f, Interpolation.fade), Actions.remove())));
|
||||
}
|
||||
|
||||
public boolean shown(){
|
||||
return shown;
|
||||
}
|
||||
|
||||
/** Show unlock notification for a new recipe. */
|
||||
public void showUnlock(UnlockableContent content){
|
||||
//some content may not have icons... yet
|
||||
if(content.getContentIcon() == null) return;
|
||||
|
||||
//if there's currently no unlock notification...
|
||||
if(lastUnlockTable == null){
|
||||
Table table = new Table("button");
|
||||
table.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
table.remove();
|
||||
lastUnlockLayout = null;
|
||||
lastUnlockTable = null;
|
||||
}
|
||||
});
|
||||
table.margin(12);
|
||||
|
||||
Table in = new Table();
|
||||
|
||||
//create texture stack for displaying
|
||||
Image image = new Image(content.getContentIcon());
|
||||
image.setScaling(Scaling.fit);
|
||||
|
||||
in.add(image).size(48f).pad(2);
|
||||
|
||||
//add to table
|
||||
table.add(in).padRight(8);
|
||||
table.add("$unlocked");
|
||||
table.pack();
|
||||
|
||||
//create container table which will align and move
|
||||
Table container = Core.scene.table();
|
||||
container.top().add(table);
|
||||
container.setTranslation(0, table.getPrefHeight());
|
||||
container.actions(Actions.translateBy(0, -table.getPrefHeight(), 1f, Interpolation.fade), Actions.delay(4f),
|
||||
//nesting actions() calls is necessary so the right prefHeight() is used
|
||||
Actions.run(() -> container.actions(Actions.translateBy(0, table.getPrefHeight(), 1f, Interpolation.fade), Actions.run(() -> {
|
||||
lastUnlockTable = null;
|
||||
lastUnlockLayout = null;
|
||||
}), Actions.remove())));
|
||||
|
||||
lastUnlockTable = container;
|
||||
lastUnlockLayout = in;
|
||||
}else{
|
||||
//max column size
|
||||
int col = 3;
|
||||
//max amount of elements minus extra 'plus'
|
||||
int cap = col * col - 1;
|
||||
|
||||
//get old elements
|
||||
Array<Element> elements = new Array<>(lastUnlockLayout.getChildren());
|
||||
int esize = elements.size;
|
||||
|
||||
//...if it's already reached the cap, ignore everything
|
||||
if(esize > cap) return;
|
||||
|
||||
//get size of each element
|
||||
float size = 48f / Math.min(elements.size + 1, col);
|
||||
|
||||
lastUnlockLayout.clearChildren();
|
||||
lastUnlockLayout.defaults().size(size).pad(2);
|
||||
|
||||
for(int i = 0; i < esize && i <= cap; i++){
|
||||
lastUnlockLayout.add(elements.get(i));
|
||||
|
||||
if(i % col == col - 1){
|
||||
lastUnlockLayout.row();
|
||||
}
|
||||
}
|
||||
|
||||
//if there's space, add it
|
||||
if(esize < cap){
|
||||
|
||||
Image image = new Image(content.getContentIcon());
|
||||
image.setScaling(Scaling.fit);
|
||||
|
||||
lastUnlockLayout.add(image);
|
||||
}else{ //else, add a specific icon to denote no more space
|
||||
lastUnlockLayout.addImage("icon-add");
|
||||
}
|
||||
|
||||
lastUnlockLayout.pack();
|
||||
}
|
||||
}
|
||||
|
||||
public void showLaunch(){
|
||||
Image image = new Image("white");
|
||||
image.getColor().a = 0f;
|
||||
image.setFillParent(true);
|
||||
image.actions(Actions.fadeIn(40f / 60f));
|
||||
image.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
image.remove();
|
||||
}
|
||||
});
|
||||
Core.scene.add(image);
|
||||
}
|
||||
|
||||
private void toggleMenus(){
|
||||
if(flip != null){
|
||||
flip.getStyle().imageUp = Core.scene.skin.getDrawable(shown ? "icon-arrow-down" : "icon-arrow-up");
|
||||
}
|
||||
|
||||
shown = !shown;
|
||||
if(flip != null){
|
||||
flip.getParent().act(Core.graphics.getDeltaTime());
|
||||
}
|
||||
}
|
||||
|
||||
private void addWaveTable(TextButton table){
|
||||
StringBuilder ibuild = new StringBuilder();
|
||||
|
||||
IntFormat wavef = new IntFormat("wave");
|
||||
IntFormat enemyf = new IntFormat("wave.enemy");
|
||||
IntFormat enemiesf = new IntFormat("wave.enemies");
|
||||
IntFormat waitingf = new IntFormat("wave.waiting", i -> {
|
||||
ibuild.setLength(0);
|
||||
int m = i/60;
|
||||
int s = i % 60;
|
||||
if(m <= 0){
|
||||
ibuild.append(s);
|
||||
}else{
|
||||
ibuild.append(m);
|
||||
ibuild.append(":");
|
||||
if(s < 10){
|
||||
ibuild.append("0");
|
||||
}
|
||||
ibuild.append(s);
|
||||
}
|
||||
return ibuild.toString();
|
||||
});
|
||||
|
||||
table.clearChildren();
|
||||
table.touchable(Touchable.enabled);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
table.labelWrap(() -> {
|
||||
builder.setLength(0);
|
||||
builder.append(wavef.get(state.wave));
|
||||
builder.append("\n");
|
||||
|
||||
if(state.enemies() > 0){
|
||||
if(state.enemies() == 1){
|
||||
builder.append(enemyf.get(state.enemies()));
|
||||
}else{
|
||||
builder.append(enemiesf.get(state.enemies()));
|
||||
}
|
||||
builder.append("\n");
|
||||
}
|
||||
|
||||
if(state.rules.waveTimer){
|
||||
builder.append((state.rules.waitForWaveToEnd && unitGroups[waveTeam.ordinal()].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60))));
|
||||
}else if(state.enemies() == 0){
|
||||
builder.append(Core.bundle.get("waiting"));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}).growX().pad(8f);
|
||||
|
||||
table.setDisabled(true);
|
||||
table.visible(() -> state.rules.waves);
|
||||
}
|
||||
|
||||
private void addPlayButton(Table table){
|
||||
table.right().addImageButton("icon-play", "right", 30f, () -> {
|
||||
if(Net.client() && player.isAdmin){
|
||||
Call.onAdminRequest(player, AdminAction.wave);
|
||||
}else{
|
||||
state.wavetime = 0f;
|
||||
}
|
||||
}).growY().fillX().right().width(40f)
|
||||
.visible(() -> state.rules.waves && ((Net.server() || player.isAdmin) || !Net.active()) && state.enemies() == 0
|
||||
&& !world.spawner.isSpawning());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,54 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.Label;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.Label;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
public class LoadingFragment implements Fragment {
|
||||
public class LoadingFragment extends Fragment{
|
||||
private Table table;
|
||||
private TextButton button;
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
public void build(Group parent){
|
||||
parent.fill("loadDim", t -> {
|
||||
t.visible(false);
|
||||
t.touchable(Touchable.enabled);
|
||||
t.add().height(70f).row();
|
||||
|
||||
table = new table("loadDim"){{
|
||||
touchable(Touchable.enabled);
|
||||
get().addImage("white").growX()
|
||||
.height(3f).pad(4f).growX().get().setColor(Colors.get("accent"));
|
||||
row();
|
||||
new label("$text.loading"){{
|
||||
get().setName("namelabel");
|
||||
}}.pad(10);
|
||||
row();
|
||||
get().addImage("white").growX()
|
||||
.height(3f).pad(4f).growX().get().setColor(Colors.get("accent"));
|
||||
}}.end().get();
|
||||
t.addImage("white").growX().height(3f).pad(4f).growX().get().setColor(Pal.accent);
|
||||
t.row();
|
||||
t.add("$loading").name("namelabel").pad(10f);
|
||||
t.row();
|
||||
t.addImage("white").growX().height(3f).pad(4f).growX().get().setColor(Pal.accent);
|
||||
t.row();
|
||||
|
||||
table.setVisible(false);
|
||||
button = t.addButton("$cancel", () -> {
|
||||
}).pad(20).size(250f, 70f).visible(false).get();
|
||||
table = t;
|
||||
});
|
||||
}
|
||||
|
||||
public void setButton(Runnable listener){
|
||||
button.visible(true);
|
||||
button.getListeners().remove(button.getListeners().size - 1);
|
||||
button.clicked(listener);
|
||||
}
|
||||
|
||||
public void show(){
|
||||
show("$text.loading");
|
||||
show("$loading");
|
||||
}
|
||||
|
||||
public void show(String text){
|
||||
table.<Label>find("namelabel").setText(text);
|
||||
table.setVisible(true);
|
||||
table.visible(true);
|
||||
table.toFront();
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
table.setVisible(false);
|
||||
table.visible(false);
|
||||
button.visible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,152 +1,156 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.game.EventType.ResizeEvent;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.ui.MenuButton;
|
||||
import io.anuke.mindustry.ui.MobileButton;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MenuFragment implements Fragment{
|
||||
|
||||
public void build(){
|
||||
new table(){{
|
||||
visible(() -> state.is(State.menu));
|
||||
public class MenuFragment extends Fragment{
|
||||
private Table container;
|
||||
|
||||
if(!mobile){
|
||||
new table(){{
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
parent.fill(c -> {
|
||||
container = c;
|
||||
container.visible(() -> state.is(State.menu));
|
||||
|
||||
float w = 200f;
|
||||
float bw = w * 2f + 10f;
|
||||
if(!mobile){
|
||||
buildDesktop();
|
||||
}else{
|
||||
buildMobile();
|
||||
Events.on(ResizeEvent.class, event -> buildMobile());
|
||||
}
|
||||
});
|
||||
|
||||
defaults().size(w, 70f).padTop(5).padRight(5);
|
||||
//discord icon in top right
|
||||
parent.fill(c -> c.top().right().addButton("", "discord", ui.discord::show).size(84, 45)
|
||||
.visible(() -> state.is(State.menu)));
|
||||
|
||||
add(new MenuButton("icon-play-2", "$text.play", MenuFragment.this::showPlaySelect)).width(bw).colspan(2);
|
||||
//info icon
|
||||
if(mobile){
|
||||
parent.fill(c -> c.top().left().addButton("", "info", ui.about::show).size(84, 45)
|
||||
.visible(() -> state.is(State.menu)));
|
||||
}
|
||||
|
||||
row();
|
||||
//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)));
|
||||
}
|
||||
|
||||
add(new MenuButton("icon-editor", "$text.editor", () -> {
|
||||
if(gwt){
|
||||
ui.showInfo("$text.editor.web");
|
||||
}else{
|
||||
ui.editor.show();
|
||||
}
|
||||
}));
|
||||
|
||||
add(new MenuButton("icon-tools", "$text.settings", ui.settings::show));
|
||||
private void buildMobile(){
|
||||
container.clear();
|
||||
container.setSize(Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
|
||||
row();
|
||||
float size = 120f;
|
||||
float isize = iconsize;
|
||||
container.defaults().size(size).pad(5).padTop(4f);
|
||||
|
||||
add(new MenuButton("icon-info", "$text.about.button", ui.about::show));
|
||||
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),
|
||||
join = new MobileButton("icon-add", isize, "$joingame", ui.join::show),
|
||||
editor = new MobileButton("icon-editor", isize, "$editor", () -> ui.loadAnd(ui.editor::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());
|
||||
|
||||
add(new MenuButton("icon-menu", OS.isMac ? "$text.credits" : "$text.changelog.title", () -> {
|
||||
if(OS.isMac){
|
||||
ui.about.showCredits();
|
||||
}else {
|
||||
ui.changelog.show();
|
||||
}
|
||||
}));
|
||||
if(!Core.graphics.isPortrait()){
|
||||
container.add(play);
|
||||
container.add(join);
|
||||
container.add(custom);
|
||||
container.add(maps);
|
||||
container.row();
|
||||
|
||||
row();
|
||||
|
||||
if(!gwt){
|
||||
add(new MenuButton("icon-exit", "$text.quit", Gdx.app::exit)).width(bw).colspan(2);
|
||||
}
|
||||
container.table(table -> {
|
||||
table.defaults().set(container.defaults());
|
||||
|
||||
get().margin(16);
|
||||
}}.end();
|
||||
table.add(editor);
|
||||
table.add(tools);
|
||||
|
||||
}else {
|
||||
new table() {{
|
||||
float size = 120f;
|
||||
defaults().size(size).pad(5);
|
||||
float isize = 14f * 4;
|
||||
if(Platform.instance.canDonate()) table.add(donate);
|
||||
table.add(exit);
|
||||
}).colspan(4);
|
||||
}else{
|
||||
container.add(play);
|
||||
container.add(maps);
|
||||
container.row();
|
||||
container.add(custom);
|
||||
container.add(join);
|
||||
container.row();
|
||||
container.add(editor);
|
||||
container.add(tools);
|
||||
container.row();
|
||||
|
||||
new imagebutton("icon-play-2", isize, ui.levels::show).text("$text.play").padTop(4f);
|
||||
container.table(table -> {
|
||||
table.defaults().set(container.defaults());
|
||||
|
||||
new imagebutton("icon-tutorial", isize, () -> control.playMap(world.maps().getMap("tutorial"))).text("$text.tutorial").padTop(4f);
|
||||
if(Platform.instance.canDonate()) table.add(donate);
|
||||
table.add(exit);
|
||||
}).colspan(2);
|
||||
}
|
||||
}
|
||||
|
||||
new imagebutton("icon-load", isize, ui.load::show).text("$text.load").padTop(4f);
|
||||
private void buildDesktop(){
|
||||
container.table(out -> {
|
||||
|
||||
new imagebutton("icon-add", isize, ui.join::show).text("$text.joingame").padTop(4f);
|
||||
float w = 200f;
|
||||
float bw = w * 2f + 10f;
|
||||
|
||||
row();
|
||||
out.margin(16);
|
||||
out.defaults().size(w, 66f).padTop(5).padRight(5);
|
||||
|
||||
new table(){{
|
||||
out.add(new MenuButton("icon-play-2", "$play", ui.deploy::show)).width(bw).colspan(2);
|
||||
|
||||
defaults().size(size).pad(5);
|
||||
out.row();
|
||||
|
||||
new imagebutton("icon-editor", isize, ui.editor::show).text("$text.editor").padTop(4f);
|
||||
out.add(new MenuButton("icon-add", "$joingame", ui.join::show));
|
||||
|
||||
new imagebutton("icon-tools", isize, ui.settings::show).text("$text.settings").padTop(4f);
|
||||
out.add(new MenuButton("icon-play-custom", "$customgame", this::showCustomSelect));
|
||||
|
||||
new imagebutton("icon-info", isize, ui.about::show).text("$text.about.button").padTop(4f);
|
||||
out.row();
|
||||
|
||||
if (!ios) {
|
||||
new imagebutton("icon-donate", isize, Platform.instance::openDonations).text("$text.donate").padTop(4f);
|
||||
}
|
||||
out.add(new MenuButton("icon-editor", "$editor", () -> ui.loadAnd(ui.editor::show)));
|
||||
|
||||
}}.colspan(4).end();
|
||||
}}.end();
|
||||
}
|
||||
}}.end();
|
||||
out.add(new MenuButton("icon-map", "$maps", ui.maps::show));
|
||||
|
||||
//discord icon in top right
|
||||
if(Platform.instance.hasDiscord()) {
|
||||
new table() {{
|
||||
abottom().atop().aright();
|
||||
get().addButton("", "discord", ui.discord::show);
|
||||
}}.end().visible(() -> state.is(State.menu));
|
||||
}
|
||||
out.row();
|
||||
|
||||
//version info
|
||||
new table(){{
|
||||
visible(() -> state.is(State.menu));
|
||||
abottom().aleft();
|
||||
new label("Mindustry " + Version.code + " " + Version.type + " / " + Version.buildName);
|
||||
}}.end();
|
||||
}
|
||||
out.add(new MenuButton("icon-info", "$about.button", ui.about::show));
|
||||
|
||||
private void showPlaySelect(){
|
||||
float w = 200f;
|
||||
float bw = w * 2f + 10f;
|
||||
out.add(new MenuButton("icon-tools", "$settings", ui.settings::show));
|
||||
|
||||
FloatingDialog dialog = new FloatingDialog("$text.play");
|
||||
dialog.addCloseButton();
|
||||
dialog.content().defaults().height(70f).width(w).padRight(5f);
|
||||
out.row();
|
||||
|
||||
dialog.content().add(new MenuButton("icon-play-2", "$text.newgame", () -> {
|
||||
dialog.hide();
|
||||
ui.levels.show();
|
||||
})).width(bw).colspan(2);
|
||||
dialog.content().row();
|
||||
out.add(new MenuButton("icon-exit", "$quit", Core.app::exit)).width(bw).colspan(2);
|
||||
});
|
||||
}
|
||||
|
||||
dialog.content().add(new MenuButton("icon-add", "$text.joingame", () -> {
|
||||
if(Platform.instance.canJoinGame()){
|
||||
ui.join.show();
|
||||
dialog.hide();
|
||||
}else{
|
||||
ui.showInfo("$text.multiplayer.web");
|
||||
}
|
||||
}));
|
||||
dialog.content().add(new MenuButton("icon-tutorial", "$text.tutorial", ()-> {
|
||||
control.playMap(world.maps().getMap("tutorial"));
|
||||
dialog.hide();
|
||||
}));
|
||||
|
||||
dialog.content().row();
|
||||
|
||||
dialog.content().add(new MenuButton("icon-load", "$text.loadgame", () -> {
|
||||
ui.load.show();
|
||||
dialog.hide();
|
||||
})).width(bw).colspan(2);
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import io.anuke.arc.scene.Group;
|
||||
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 Group();
|
||||
|
||||
public OverlayFragment(InputHandler input){
|
||||
inv = new BlockInventoryFragment();
|
||||
config = new BlockConfigFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
group.setFillParent(true);
|
||||
parent.addChild(group);
|
||||
|
||||
inv.build(group);
|
||||
config.build(group);
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
group.remove();
|
||||
}
|
||||
}
|
||||
@@ -1,234 +1,349 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.scene.Group;
|
||||
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.input.AndroidInput;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.game.EventType.UnlockEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.input.PlaceMode;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.scene.actions.Actions;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.scene.ui.Label;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class PlacementFragment implements Fragment{
|
||||
boolean shown = false, placing = false;
|
||||
Table breaktable, next, container;
|
||||
Label modelabel;
|
||||
|
||||
public void build(){
|
||||
if(!mobile) return;
|
||||
public class PlacementFragment extends Fragment{
|
||||
final int rowWidth = 4;
|
||||
|
||||
InputHandler input = control.input();
|
||||
Array<Block> returnArray = new Array<>();
|
||||
Array<Category> returnCatArray = new Array<>();
|
||||
boolean[] categoryEmpty = new boolean[Category.values().length];
|
||||
Category currentCategory = Category.distribution;
|
||||
Block hovered, lastDisplay;
|
||||
Tile lastHover;
|
||||
Tile hoverTile;
|
||||
Table blockTable, toggler, topTable;
|
||||
boolean lastGround;
|
||||
|
||||
float s = 50f;
|
||||
float translation = Unit.dp.scl(58f);
|
||||
//not configurable, no plans to make it configurable
|
||||
final KeyCode[] inputGrid = {
|
||||
KeyCode.NUM_1, KeyCode.NUM_2, KeyCode.NUM_3, KeyCode.NUM_4,
|
||||
KeyCode.Q, KeyCode.W, KeyCode.E, KeyCode.R,
|
||||
KeyCode.A, KeyCode.S, KeyCode.D, KeyCode.F,
|
||||
KeyCode.Z, KeyCode.X, KeyCode.C, KeyCode.V
|
||||
}, inputCatGrid = {
|
||||
KeyCode.NUM_1, KeyCode.NUM_2,
|
||||
KeyCode.Q, KeyCode.W,
|
||||
KeyCode.A, KeyCode.S,
|
||||
KeyCode.Z, KeyCode.X, KeyCode.C, KeyCode.V
|
||||
};
|
||||
|
||||
new table(){{
|
||||
visible(() -> !state.is(State.menu));
|
||||
public PlacementFragment(){
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
Core.app.post(() -> {
|
||||
control.input().block = null;
|
||||
rebuild();
|
||||
});
|
||||
});
|
||||
|
||||
abottom();
|
||||
aleft();
|
||||
Events.on(UnlockEvent.class, event -> {
|
||||
if(event.content instanceof Block){
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ButtonGroup<ImageButton> placeGroup = new ButtonGroup<>();
|
||||
ButtonGroup<ImageButton> breakGroup = new ButtonGroup<>();
|
||||
void rebuild(){
|
||||
currentCategory = Category.turret;
|
||||
Group group = toggler.getParent();
|
||||
int index = toggler.getZIndex();
|
||||
toggler.remove();
|
||||
build(group);
|
||||
toggler.setZIndex(index);
|
||||
}
|
||||
|
||||
update(t -> {
|
||||
if((input.recipe == null) == placing){
|
||||
float i = 0.1f;
|
||||
Interpolation n = Interpolation.pow3Out;
|
||||
if(input.recipe == null){
|
||||
placing = false;
|
||||
container.clearActions();
|
||||
container.actions(Actions.translateBy(0, -(container.getTranslation().y + translation), i, n));
|
||||
if (!input.lastBreakMode.both) input.placeMode = input.lastBreakMode;
|
||||
}else{
|
||||
placing = true;
|
||||
container.clearActions();
|
||||
container.actions(Actions.translateBy(0, -(container.getTranslation().y), i, n));
|
||||
input.placeMode = input.lastPlaceMode;
|
||||
}
|
||||
}
|
||||
boolean gridUpdate(InputHandler input){
|
||||
if(Core.input.keyDown(Binding.pick)){ //mouse eyedropper select
|
||||
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
|
||||
if(!input.placeMode.delete){
|
||||
placeGroup.setMinCheckCount(1);
|
||||
for(ImageButton button : placeGroup.getButtons()){
|
||||
if(button.getName().equals(input.placeMode.name())){
|
||||
button.setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
placeGroup.setMinCheckCount(0);
|
||||
for(ImageButton button : placeGroup.getButtons())
|
||||
button.setChecked(false);
|
||||
}
|
||||
if(tile != null){
|
||||
tile = tile.link();
|
||||
Block tryRecipe = tile.block();
|
||||
if(tryRecipe.isVisible() && unlocked(tryRecipe)){
|
||||
input.block = tryRecipe;
|
||||
currentCategory = input.block.buildCategory;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(input.placeMode.delete || input.breakMode.both){
|
||||
PlaceMode mode = input.breakMode;
|
||||
breakGroup.setMinCheckCount(1);
|
||||
for(ImageButton button : breakGroup.getButtons()){
|
||||
if(button.getName().equals(mode.name())){
|
||||
button.setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
breakGroup.setMinCheckCount(0);
|
||||
for(ImageButton button : breakGroup.getButtons())
|
||||
button.setChecked(false);
|
||||
}
|
||||
});
|
||||
if(!Core.input.keyDown(Binding.gridMode) || ui.chatfrag.chatOpen()) return false;
|
||||
if(Core.input.keyDown(Binding.gridModeShift)){ //select category
|
||||
int i = 0;
|
||||
for(KeyCode key : inputCatGrid){
|
||||
if(Core.input.keyDown(key)){
|
||||
input.block = getByCategory(Category.values()[i]).first();
|
||||
currentCategory = input.block.buildCategory;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}else{ //select block
|
||||
int i = 0;
|
||||
Array<Block> recipes = getByCategory(currentCategory);
|
||||
for(KeyCode key : inputGrid){
|
||||
if(Core.input.keyDown(key))
|
||||
input.block = (i < recipes.size && unlocked(recipes.get(i))) ? recipes.get(i) : null;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
container = new table(){{
|
||||
modelabel = new label("").get();
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
parent.fill(full -> {
|
||||
toggler = full;
|
||||
full.bottom().right().visible(() -> !state.is(State.menu) && ui.hudfrag.shown());
|
||||
|
||||
row();
|
||||
full.table(frame -> {
|
||||
InputHandler input = control.input();
|
||||
|
||||
//break menu
|
||||
new table() {{
|
||||
abottom();
|
||||
aleft();
|
||||
//rebuilds the category table with the correct recipes
|
||||
Runnable rebuildCategory = () -> {
|
||||
blockTable.clear();
|
||||
blockTable.top().margin(5);
|
||||
|
||||
height(s + 5 + 4);
|
||||
int index = 0;
|
||||
|
||||
next = new table("pane") {{
|
||||
margin(5f);
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
group.setMinCheckCount(0);
|
||||
|
||||
defaults().padBottom(-5.5f);
|
||||
for(Block block : getByCategory(currentCategory)){
|
||||
if(index++ % rowWidth == 0){
|
||||
blockTable.row();
|
||||
}
|
||||
|
||||
new imagebutton("icon-arrow-right", 10 * 3, () -> {
|
||||
toggle(!shown);
|
||||
}).update(l -> l.getStyle().imageUp = Core.skin.getDrawable(shown ? "icon-arrow-left" : "icon-" + input.breakMode.name())).size(s, s + 4);
|
||||
if(!unlocked(block)){
|
||||
blockTable.add().size(46);
|
||||
continue;
|
||||
}
|
||||
|
||||
}}.end().get();
|
||||
ImageButton button = blockTable.addImageButton("icon-locked", "select", 8 * 4, () -> {
|
||||
if(unlocked(block)){
|
||||
input.block = input.block == block ? null : block;
|
||||
}
|
||||
}).size(46f).group(group).get();
|
||||
|
||||
breaktable = new table("pane") {{
|
||||
visible(() -> shown);
|
||||
margin(5f);
|
||||
marginLeft(-(Unit.dp.scl(1f) - 1f) * 2.5f);
|
||||
touchable(Touchable.enabled);
|
||||
aleft();
|
||||
button.getStyle().imageUp = new TextureRegionDrawable(block.icon(Icon.medium));
|
||||
|
||||
defaults().size(s, s + 4);
|
||||
button.update(() -> { //color unplacable things gray
|
||||
TileEntity core = player.getClosestCore();
|
||||
Color color = state.rules.infiniteResources || (core != null && (core.items.has(block.buildRequirements, state.rules.buildCostMultiplier) || state.rules.infiniteResources)) ? Color.WHITE : Color.GRAY;
|
||||
button.forEach(elem -> elem.setColor(color));
|
||||
button.setChecked(input.block == block);
|
||||
});
|
||||
|
||||
for (PlaceMode mode : PlaceMode.values()) {
|
||||
if (!mode.shown || !mode.delete) continue;
|
||||
button.hovered(() -> hovered = block);
|
||||
button.exited(() -> {
|
||||
if(hovered == block){
|
||||
hovered = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
//add missing elements to even out table size
|
||||
if(index < 4){
|
||||
for(int i = 0; i < 4-index; i++){
|
||||
blockTable.add().size(46f);
|
||||
}
|
||||
}
|
||||
blockTable.act(0f);
|
||||
};
|
||||
|
||||
defaults().padBottom(-5.5f);
|
||||
//top table with hover info
|
||||
frame.table("button-edge-2", top -> {
|
||||
topTable = top;
|
||||
top.add(new Table()).growX().update(topTable -> {
|
||||
//don't refresh unnecessarily
|
||||
if((tileDisplayBlock() == null && lastDisplay == getSelected() && !lastGround)
|
||||
|| (tileDisplayBlock() != null && lastHover == hoverTile && lastDisplay == tileDisplayBlock() && lastGround))
|
||||
return;
|
||||
|
||||
ImageButton button = new imagebutton("icon-" + mode.name(), "toggle", 10 * 3, () -> {
|
||||
control.input().resetCursor();
|
||||
input.breakMode = mode;
|
||||
input.lastBreakMode = mode;
|
||||
if (!mode.both){
|
||||
input.placeMode = mode;
|
||||
}else{
|
||||
input.placeMode = input.lastPlaceMode;
|
||||
}
|
||||
modeText(Bundles.format("text.mode.break", mode.toString()));
|
||||
}).group(breakGroup).get();
|
||||
topTable.clear();
|
||||
topTable.top().left().margin(5);
|
||||
|
||||
button.setName(mode.name());
|
||||
button.released(() -> {
|
||||
//TODO hack
|
||||
if(mode == PlaceMode.areaDelete){
|
||||
((AndroidInput)input).placing = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
lastHover = hoverTile;
|
||||
lastDisplay = getSelected();
|
||||
lastGround = tileDisplayBlock() != null;
|
||||
|
||||
}}.end().get();
|
||||
if(lastDisplay != null){ //show selected recipe
|
||||
lastGround = false;
|
||||
|
||||
breaktable.getParent().swapActor(breaktable, next);
|
||||
topTable.table(header -> {
|
||||
header.left();
|
||||
header.add(new Image(lastDisplay.icon(Icon.medium))).size(8 * 4);
|
||||
header.labelWrap(() -> !unlocked(lastDisplay) ? Core.bundle.get("block.unknown") : lastDisplay.localizedName)
|
||||
.left().width(190f).padLeft(5);
|
||||
header.add().growX();
|
||||
if(unlocked(lastDisplay)){
|
||||
header.addButton("?", "clear-partial", () -> ui.content.show(lastDisplay))
|
||||
.size(8 * 5).padTop(-5).padRight(-5).right().grow();
|
||||
}
|
||||
}).growX().left();
|
||||
topTable.row();
|
||||
//add requirement table
|
||||
topTable.table(req -> {
|
||||
req.top().left();
|
||||
|
||||
breaktable.getTranslation().set(-breaktable.getPrefWidth(), 0);
|
||||
for(ItemStack stack : lastDisplay.buildRequirements){
|
||||
req.table(line -> {
|
||||
line.left();
|
||||
line.addImage(stack.item.icon(Item.Icon.small)).size(8 * 2);
|
||||
line.add(stack.item.localizedName()).color(Color.LIGHT_GRAY).padLeft(2).left();
|
||||
line.labelWrap(() -> {
|
||||
TileEntity core = player.getClosestCore();
|
||||
if(core == null || state.rules.infiniteResources) return "*/*";
|
||||
|
||||
}}.end().get();
|
||||
int amount = core.items.get(stack.item);
|
||||
int stackamount = Math.round(stack.amount * state.rules.buildCostMultiplier);
|
||||
String color = (amount < stackamount / 2f ? "[red]" : amount < stackamount ? "[accent]" : "[white]");
|
||||
|
||||
row();
|
||||
return color + ui.formatAmount(amount) + "[white]/" + stackamount;
|
||||
}).padLeft(5);
|
||||
}).left();
|
||||
req.row();
|
||||
}
|
||||
}).growX().left().margin(3);
|
||||
|
||||
//place menu
|
||||
new table() {{
|
||||
touchable(Touchable.enabled);
|
||||
}else if(tileDisplayBlock() != null){ //show selected tile
|
||||
lastDisplay = tileDisplayBlock();
|
||||
topTable.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(lastDisplay.getDisplayIcon(hoverTile))).size(8 * 4);
|
||||
t.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
if(hoverTile.getTeam() == player.getTeam()){
|
||||
topTable.row();
|
||||
topTable.table(t -> {
|
||||
t.left().defaults().left();
|
||||
lastDisplay.display(hoverTile, t);
|
||||
}).left().growX();
|
||||
}
|
||||
}
|
||||
});
|
||||
}).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.row();
|
||||
frame.table("pane-2", blocksSelect -> {
|
||||
blocksSelect.margin(4).marginTop(0);
|
||||
blocksSelect.table(blocks -> blockTable = blocks).grow();
|
||||
blocksSelect.row();
|
||||
blocksSelect.table(input::buildUI).growX();
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
frame.table(categories -> {
|
||||
categories.defaults().size(50f);
|
||||
|
||||
aleft();
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
|
||||
new table("pane") {{
|
||||
margin(5f);
|
||||
aleft();
|
||||
//update category empty values
|
||||
for(Category cat : Category.values()){
|
||||
Array<Block> blocks = getByCategory(cat);
|
||||
categoryEmpty[cat.ordinal()] = blocks.isEmpty() || !unlocked(blocks.first());
|
||||
}
|
||||
|
||||
defaults().size(s, s + 4).padBottom(-5.5f);
|
||||
int f = 0;
|
||||
for(Category cat : getCategories()){
|
||||
if(f++ % 2 == 0) categories.row();
|
||||
|
||||
Color color = Color.GRAY;
|
||||
if(categoryEmpty[cat.ordinal()]){
|
||||
categories.addImage("flat");
|
||||
continue;
|
||||
}
|
||||
|
||||
new imagebutton("icon-cancel", 14 * 3, () -> {
|
||||
input.recipe = null;
|
||||
}).imageColor(color)
|
||||
.visible(() -> input.recipe != null);
|
||||
categories.addImageButton("icon-" + cat.name(), "clear-toggle", iconsize, () -> {
|
||||
currentCategory = cat;
|
||||
rebuildCategory.run();
|
||||
}).group(group).update(i -> i.setChecked(currentCategory == cat));
|
||||
}
|
||||
}).touchable(Touchable.enabled);
|
||||
|
||||
for (PlaceMode mode : PlaceMode.values()) {
|
||||
if (!mode.shown || mode.delete) continue;
|
||||
rebuildCategory.run();
|
||||
frame.update(() -> {
|
||||
if(gridUpdate(input)) rebuildCategory.run();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
new imagebutton("icon-" + mode.name(), "toggle", 10 * 3, () -> {
|
||||
control.input().resetCursor();
|
||||
input.placeMode = mode;
|
||||
input.lastPlaceMode = mode;
|
||||
modeText(Bundles.format("text.mode.place", mode.toString()));
|
||||
}).group(placeGroup).get().setName(mode.name());
|
||||
}
|
||||
Array<Category> getCategories(){
|
||||
returnCatArray.clear();
|
||||
returnCatArray.addAll(Category.values());
|
||||
returnCatArray.sort((c1, c2) -> Boolean.compare(categoryEmpty[c1.ordinal()], categoryEmpty[c2.ordinal()]));
|
||||
return returnCatArray;
|
||||
}
|
||||
|
||||
new imagebutton("icon-arrow", 14 * 3, () -> {
|
||||
input.rotation = Mathf.mod(input.rotation + 1, 4);
|
||||
}).imageColor(color).visible(() -> input.recipe != null).update(image -> {
|
||||
image.getImage().setRotation(input.rotation * 90);
|
||||
image.getImage().setOrigin(Align.center);
|
||||
});
|
||||
Array<Block> getByCategory(Category cat){
|
||||
returnArray.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.buildCategory == cat && block.isVisible()){
|
||||
returnArray.add(block);
|
||||
}
|
||||
}
|
||||
returnArray.sort((b1, b2) -> -Boolean.compare(unlocked(b1), unlocked(b2)));
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
}}.left().end();
|
||||
}}.left().end();
|
||||
boolean unlocked(Block block){
|
||||
return !world.isZone() || data.isUnlocked(block);
|
||||
}
|
||||
|
||||
}}.end().get();
|
||||
/** Returns the currently displayed block in the top box. */
|
||||
Block getSelected(){
|
||||
Block toDisplay = null;
|
||||
|
||||
container.setTranslation(0, -translation);
|
||||
Vector2 v = topTable.stageToLocalCoordinates(Core.input.mouse());
|
||||
|
||||
}}.end();
|
||||
}
|
||||
//setup hovering tile
|
||||
if(!Core.scene.hasMouse() && topTable.hit(v.x, v.y, false) == null){
|
||||
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(tile != null){
|
||||
hoverTile = tile.link();
|
||||
}else{
|
||||
hoverTile = null;
|
||||
}
|
||||
}else{
|
||||
hoverTile = null;
|
||||
}
|
||||
|
||||
private void modeText(String text){
|
||||
modelabel.setText(text);
|
||||
modelabel.clearActions();
|
||||
modelabel.setColor(Color.WHITE);
|
||||
modelabel.actions(Actions.fadeOut(5f, Interpolation.fade));
|
||||
}
|
||||
//block currently selected
|
||||
if(control.input().block != null){
|
||||
toDisplay = control.input().block;
|
||||
}
|
||||
|
||||
private void toggle(boolean show){
|
||||
float dur = 0.3f;
|
||||
Interpolation in = Interpolation.pow3Out;
|
||||
//block hovered on in build menu
|
||||
if(hovered != null){
|
||||
toDisplay = hovered;
|
||||
}
|
||||
|
||||
if(breaktable.getActions().size != 0 || shown == show) return;
|
||||
return toDisplay;
|
||||
}
|
||||
|
||||
breaktable.getParent().swapActor(breaktable, next);
|
||||
|
||||
if(!show){
|
||||
control.input().breakMode = PlaceMode.none;
|
||||
if(control.input().placeMode.delete) control.input().placeMode = PlaceMode.none;
|
||||
breaktable.actions(Actions.translateBy(-breaktable.getWidth() - 5, 0, dur, in), Actions.call(() -> shown = false));
|
||||
}else{
|
||||
shown = true;
|
||||
breaktable.actions(Actions.translateBy(-breaktable.getTranslation().x - 5, 0, dur, in));
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Returns the block currently being hovered over in the world. */
|
||||
Block tileDisplayBlock(){
|
||||
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : null;
|
||||
}
|
||||
}
|
||||
@@ -1,89 +1,63 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.arc.Core;
|
||||
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.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.util.Interval;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.mindustry.net.Packets.AdminAction;
|
||||
import io.anuke.mindustry.net.Packets.KickReason;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
import io.anuke.ucore.core.Inputs;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.builders.button;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Stack;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class PlayerListFragment implements Fragment{
|
||||
public boolean visible = false;
|
||||
Table content = new Table();
|
||||
int last = 0;
|
||||
public class PlayerListFragment extends Fragment{
|
||||
private boolean visible = false;
|
||||
private Table content = new Table().marginRight(13f).marginLeft(13f);
|
||||
private Interval timer = new Interval();
|
||||
|
||||
@Override
|
||||
public void build(){
|
||||
new table(){{
|
||||
new table("pane"){{
|
||||
touchable(Touchable.enabled);
|
||||
margin(14f);
|
||||
new label(() -> Bundles.format(playerGroup.size() == 1 ? "text.players.single" :
|
||||
"text.players", playerGroup.size()));
|
||||
row();
|
||||
content.marginRight(13f).marginLeft(13f);
|
||||
ScrollPane pane = new ScrollPane(content, "clear");
|
||||
pane.setScrollingDisabled(true, false);
|
||||
pane.setFadeScrollBars(false);
|
||||
add(pane).grow();
|
||||
row();
|
||||
new table("pane"){{
|
||||
margin(12f);
|
||||
|
||||
get().addCheck("$text.server.friendlyfire", b -> {
|
||||
state.friendlyFire = b;
|
||||
NetEvents.handleFriendlyFireChange(b);
|
||||
}).growX().update(i -> i.setChecked(state.friendlyFire)).disabled(b -> Net.client()).padRight(5);
|
||||
|
||||
new button("$text.server.bans", () -> {
|
||||
ui.bans.show();
|
||||
}).padTop(-12).padBottom(-12).fillY().cell.disabled(b -> Net.client());
|
||||
|
||||
new button("$text.server.admins", () -> {
|
||||
ui.admins.show();
|
||||
}).padTop(-12).padBottom(-12).padRight(-12).fillY().cell.disabled(b -> Net.client());
|
||||
|
||||
new button("$text.server.rollback", () -> {
|
||||
ui.rollback.show();
|
||||
}).padTop(-12).padBottom(-12).padRight(-12).fillY().cell.disabled(b -> !player.isAdmin);
|
||||
|
||||
}}.pad(10f).growX().end();
|
||||
}}.end();
|
||||
|
||||
update(t -> {
|
||||
if(!mobile){
|
||||
if(Inputs.keyTap("player_list")){
|
||||
visible = !visible;
|
||||
}
|
||||
}
|
||||
public void build(Group parent){
|
||||
parent.fill(cont -> {
|
||||
cont.visible(() -> visible);
|
||||
cont.update(() -> {
|
||||
if(!(Net.active() && !state.is(State.menu))){
|
||||
visible = false;
|
||||
return;
|
||||
}
|
||||
if(playerGroup.size() != last){
|
||||
|
||||
if(visible && timer.get(20)){
|
||||
rebuild();
|
||||
last = playerGroup.size();
|
||||
content.pack();
|
||||
content.act(Core.graphics.getDeltaTime());
|
||||
//TODO hack
|
||||
Core.scene.act(0f);
|
||||
}
|
||||
});
|
||||
|
||||
visible(() -> visible);
|
||||
}}.end();
|
||||
cont.table("button", pane -> {
|
||||
pane.label(() -> Core.bundle.format(playerGroup.size() == 1 ? "players.single" : "players", playerGroup.size()));
|
||||
pane.row();
|
||||
pane.pane(content).grow().get().setScrollingDisabled(true, false);
|
||||
pane.row();
|
||||
|
||||
pane.table(menu -> {
|
||||
menu.defaults().growX().height(50f).fillY();
|
||||
|
||||
menu.addButton("$server.bans", ui.bans::show).disabled(b -> Net.client());
|
||||
menu.addButton("$server.admins", ui.admins::show).disabled(b -> Net.client());
|
||||
menu.addButton("$close", this::toggle);
|
||||
}).margin(0f).pad(10f).growX();
|
||||
|
||||
}).touchable(Touchable.enabled).margin(14f);
|
||||
});
|
||||
|
||||
rebuild();
|
||||
}
|
||||
@@ -93,100 +67,86 @@ public class PlayerListFragment implements Fragment{
|
||||
|
||||
float h = 74f;
|
||||
|
||||
for(Player player : playerGroup.all()){
|
||||
NetConnection connection = gwt ? null : Net.getConnection(player.clientid);
|
||||
playerGroup.all().sort((p1, p2) -> p1.getTeam().compareTo(p2.getTeam()));
|
||||
playerGroup.all().each(user -> {
|
||||
NetConnection connection = user.con;
|
||||
|
||||
if(connection == null && Net.server() && !player.isLocal) continue;
|
||||
if(connection == null && Net.server() && !user.isLocal) return;
|
||||
|
||||
Table button = new Table("button");
|
||||
Table button = new Table();
|
||||
button.left();
|
||||
button.margin(5).marginBottom(10);
|
||||
|
||||
Stack stack = new Stack();
|
||||
BorderImage image = new BorderImage(Draw.region(player.isAndroid ? "ship-standard" : "mech-standard-icon"), 3f);
|
||||
Table table = new Table(){
|
||||
@Override
|
||||
public void draw(){
|
||||
super.draw();
|
||||
Draw.color(Pal.accent);
|
||||
Draw.alpha(parentAlpha);
|
||||
Lines.stroke(Unit.dp.scl(3f));
|
||||
Lines.rect(x, y, width, height);
|
||||
Draw.reset();
|
||||
}
|
||||
};
|
||||
table.margin(8);
|
||||
table.add(new Image(user.mech.iconRegion)).grow();
|
||||
|
||||
stack.add(image);
|
||||
|
||||
if(!player.isAndroid) {
|
||||
|
||||
stack.add(new Element(){
|
||||
public void draw(){
|
||||
float s = getWidth() / 12f;
|
||||
for(int i : Mathf.signs){
|
||||
Draw.rect((i < 0 ? player.weaponLeft.name : player.weaponRight.name)
|
||||
+ "-equip", x + s * 6 + i * 3*s, y + s*6 + 2*s, -8*s*i, 8*s);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
button.add(stack).size(h);
|
||||
button.labelWrap("[#" + player.getColor().toString().toUpperCase() + "]" + player.name).width(170f).pad(10);
|
||||
button.add(table).size(h);
|
||||
button.labelWrap("[#" + user.color.toString().toUpperCase() + "]" + user.name).width(170f).pad(10);
|
||||
button.add().grow();
|
||||
|
||||
button.addImage("icon-admin").size(14*2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5);
|
||||
button.addImage("icon-admin").size(iconsize).visible(() -> user.isAdmin && !(!user.isLocal && Net.server())).padRight(5).get().updateVisibility();
|
||||
|
||||
if((Net.server() || Vars.player.isAdmin) && !player.isLocal && (!player.isAdmin || Net.server())){
|
||||
if((Net.server() || player.isAdmin) && !user.isLocal && (!user.isAdmin || Net.server())){
|
||||
button.add().growY();
|
||||
|
||||
float bs = (h + 14)/2f;
|
||||
float bs = (h) / 2f;
|
||||
|
||||
button.table(t -> {
|
||||
t.defaults().size(bs - 1, bs + 3);
|
||||
t.defaults().size(bs);
|
||||
|
||||
t.addImageButton("icon-ban", 14*2, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.confirmban", () -> {
|
||||
if(Net.server()) {
|
||||
netServer.admins.banPlayerIP(connection.address);
|
||||
netServer.kick(player.clientid, KickReason.banned);
|
||||
}else{
|
||||
NetEvents.handleAdministerRequest(player, AdminAction.ban);
|
||||
}
|
||||
});
|
||||
}).padBottom(-5.1f);
|
||||
|
||||
t.addImageButton("icon-cancel", 14*2, () -> {
|
||||
if(Net.server()) {
|
||||
netServer.kick(player.clientid, KickReason.kick);
|
||||
}else{
|
||||
NetEvents.handleAdministerRequest(player, AdminAction.kick);
|
||||
}
|
||||
}).padBottom(-5.1f);
|
||||
t.addImageButton("icon-ban", "clear-partial", iconsize,
|
||||
() -> ui.showConfirm("$confirm", "$confirmban", () -> Call.onAdminRequest(user, AdminAction.ban)));
|
||||
t.addImageButton("icon-cancel", "clear-partial", iconsize,
|
||||
() -> ui.showConfirm("$confirm", "$confirmkick", () -> Call.onAdminRequest(user, AdminAction.kick)));
|
||||
|
||||
t.row();
|
||||
|
||||
t.addImageButton("icon-admin", "toggle", 14*2, () -> {
|
||||
t.addImageButton("icon-admin", "clear-toggle-partial", iconsize, () -> {
|
||||
if(Net.client()) return;
|
||||
|
||||
String id = netServer.admins.getTrace(connection.address).uuid;
|
||||
String id = user.uuid;
|
||||
|
||||
if(netServer.admins.isAdmin(id, connection.address)){
|
||||
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
|
||||
netServer.admins.unAdminPlayer(id);
|
||||
NetEvents.handleAdminSet(player, false);
|
||||
});
|
||||
ui.showConfirm("$confirm", "$confirmunadmin", () -> netServer.admins.unAdminPlayer(id));
|
||||
}else{
|
||||
ui.showConfirm("$text.confirm", "$text.confirmadmin", () -> {
|
||||
netServer.admins.adminPlayer(id, connection.address);
|
||||
NetEvents.handleAdminSet(player, true);
|
||||
});
|
||||
ui.showConfirm("$confirm", "$confirmadmin", () -> netServer.admins.adminPlayer(id, user.usid));
|
||||
}
|
||||
}).update(b ->{
|
||||
b.setChecked(player.isAdmin);
|
||||
b.setDisabled(Net.client());
|
||||
}).get().setTouchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled);
|
||||
|
||||
t.addImageButton("icon-zoom-small", 14*2, () -> NetEvents.handleTraceRequest(player));
|
||||
|
||||
}).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs);
|
||||
})
|
||||
.update(b -> b.setChecked(user.isAdmin))
|
||||
.disabled(b -> Net.client())
|
||||
.touchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled)
|
||||
.checked(user.isAdmin);
|
||||
|
||||
t.addImageButton("icon-zoom", "clear-partial", iconsize, () -> Call.onAdminRequest(user, AdminAction.trace));
|
||||
|
||||
}).padRight(12).size(bs + 10f, bs);
|
||||
}
|
||||
|
||||
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.row();
|
||||
});
|
||||
|
||||
content.marginBottom(5);
|
||||
}
|
||||
|
||||
public void toggle(){
|
||||
visible = !visible;
|
||||
if(visible){
|
||||
rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.input.PlaceMode;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
public class ToolFragment implements Fragment{
|
||||
private Table tools;
|
||||
public int px, py, px2, py2;
|
||||
public boolean confirming;
|
||||
|
||||
public void build(){
|
||||
InputHandler input = control.input();
|
||||
|
||||
float isize = 14*3;
|
||||
|
||||
tools = new Table();
|
||||
|
||||
tools.addImageButton("icon-cancel", isize, () -> {
|
||||
if(input.placeMode == PlaceMode.areaDelete && confirming){
|
||||
confirming = false;
|
||||
}else{
|
||||
input.recipe = null;
|
||||
}
|
||||
});
|
||||
|
||||
tools.addImageButton("icon-rotate", isize, () -> {
|
||||
input.rotation++;
|
||||
input.rotation %= 4;
|
||||
});
|
||||
|
||||
tools.addImageButton("icon-check", isize, () -> {
|
||||
if(input.placeMode == PlaceMode.areaDelete && confirming){
|
||||
input.placeMode.released(px, py, px2, py2);
|
||||
confirming = false;
|
||||
}else{
|
||||
input.placeMode.tapped(control.input().getBlockX(), control.input().getBlockY());
|
||||
}
|
||||
});
|
||||
|
||||
Core.scene.add(tools);
|
||||
|
||||
tools.setVisible(() ->
|
||||
!state.is(State.menu) && mobile && ((input.recipe != null && state.inventory.hasItems(input.recipe.requirements) &&
|
||||
input.placeMode == PlaceMode.cursor) || confirming)
|
||||
);
|
||||
|
||||
tools.update(() -> {
|
||||
if(confirming){
|
||||
Vector2 v = Graphics.screen((px + px2)/2f * tilesize, Math.min(py, py2) * tilesize - tilesize*1.5f);
|
||||
tools.setPosition(v.x, v.y, Align.top);
|
||||
|
||||
}else{
|
||||
tools.setPosition(control.input().getCursorX(),
|
||||
Gdx.graphics.getHeight() - control.input().getCursorY() - 15*Core.cameraScale, Align.top);
|
||||
}
|
||||
|
||||
if(input.placeMode != PlaceMode.areaDelete){
|
||||
confirming = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user