it is done

This commit is contained in:
Anuken
2019-12-25 01:39:38 -05:00
parent 5b21873f3c
commit 514d4817c8
488 changed files with 4572 additions and 4574 deletions

View File

@@ -0,0 +1,118 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.ui.Links.*;
import static mindustry.Vars.*;
public class AboutDialog extends FloatingDialog{
private Array<String> contributors = new Array<>();
private static ObjectSet<String> bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "f-droid");
public AboutDialog(){
super("$about.button");
shown(() -> {
contributors = Array.with(Core.files.internal("contributors").readString("UTF-8").split("\n"));
Core.app.post(this::setup);
});
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);
for(LinkEntry link : Links.getLinks()){
if((ios || OS.isMac || steam) && bannedItems.contains(link.name)){
continue;
}
Table table = new Table(Tex.underline);
table.margin(0);
table.table(img -> {
img.addImage().height(h - 5).width(40f).color(link.color);
img.row();
img.addImage().height(5).width(40f).color(link.color.cpy().mul(0.8f, 0.8f, 0.8f, 1f));
}).expandY();
table.table(i -> {
i.background(Tex.buttonEdge3);
i.addImage(Core.atlas.drawable("icon-" + link.name));
}).size(h - 5, h);
table.table(inset -> {
inset.add("[accent]" + link.title).growX().left();
inset.row();
inset.labelWrap(link.description).width(w - 100f).color(Color.lightGray).growX();
}).padLeft(8);
table.addImageButton(Icon.link, () -> {
if(link.name.equals("wiki")) Events.fire(Trigger.openWiki);
if(!Core.net.openURI(link.link)){
ui.showErrorMessage("$linkfail");
Core.app.setClipboardText(link.link);
}
}).size(h - 5, h);
in.add(table).size(w, h).padTop(5).row();
}
shown(() -> Time.run(1f, () -> Core.scene.setScrollFocus(pane)));
cont.add(pane).growX();
addCloseButton();
buttons.addButton("$credits", this::showCredits).size(200f, 64f);
if(Core.graphics.isPortrait()){
for(Cell<?> cell : buttons.getCells()){
cell.width(140f);
}
}
}
public void showCredits(){
FloatingDialog dialog = new FloatingDialog("$credits");
dialog.addCloseButton();
dialog.cont.add("$credits.text");
dialog.cont.row();
if(!contributors.isEmpty()){
dialog.cont.addImage().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();
}
}

View File

@@ -0,0 +1,59 @@
package mindustry.ui.dialogs;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import mindustry.gen.*;
import mindustry.net.Administration.*;
import static mindustry.Vars.*;
public class AdminsDialog extends FloatingDialog{
public AdminsDialog(){
super("$server.admins");
addCloseButton();
setup();
shown(this::setup);
}
private void setup(){
cont.clear();
float w = 400f, h = 80f;
Table table = new Table();
ScrollPane pane = new ScrollPane(table);
pane.setFadeScrollBars(false);
if(netServer.admins.getAdmins().size == 0){
table.add("$server.admins.none");
}
for(PlayerInfo info : netServer.admins.getAdmins()){
Table res = new Table(Tex.button);
res.margin(14f);
res.labelWrap("[LIGHT_GRAY]" + info.lastName).width(w - h - 24f);
res.add().growX();
res.addImageButton(Icon.cancel, () -> {
ui.showConfirm("$confirm", "$confirmunadmin", () -> {
netServer.admins.unAdminPlayer(info.id);
playerGroup.all().each(player -> {
if(player != null && player.uuid != null && player.uuid.equals(info.id)){
player.isAdmin = false;
}
});
setup();
});
}).size(h).pad(-14f);
table.add(res).width(w).height(h);
table.row();
}
cont.add(pane);
}
}

View File

@@ -0,0 +1,55 @@
package mindustry.ui.dialogs;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import mindustry.gen.*;
import mindustry.net.Administration.*;
import static mindustry.Vars.*;
public class BansDialog extends FloatingDialog{
public BansDialog(){
super("$server.bans");
addCloseButton();
setup();
shown(this::setup);
}
private void setup(){
cont.clear();
float w = 400f, h = 80f;
Table table = new Table();
ScrollPane pane = new ScrollPane(table);
pane.setFadeScrollBars(false);
if(netServer.admins.getBanned().size == 0){
table.add("$server.bans.none");
}
for(PlayerInfo info : netServer.admins.getBanned()){
Table res = new Table(Tex.button);
res.margin(14f);
res.labelWrap("IP: [LIGHT_GRAY]" + info.lastIP + "\n[]Name: [LIGHT_GRAY]" + info.lastName).width(w - h - 24f);
res.add().growX();
res.addImageButton(Icon.cancel, () -> {
ui.showConfirm("$confirm", "$confirmunban", () -> {
netServer.admins.unbanPlayerID(info.id);
setup();
});
}).size(h).pad(-14f);
table.add(res).width(w).height(h);
table.row();
}
cont.add(pane);
}
}

View File

@@ -0,0 +1,63 @@
package mindustry.ui.dialogs;
import arc.func.*;
import arc.graphics.*;
import arc.scene.ui.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class ColorPicker extends FloatingDialog{
private Cons<Color> cons = c -> {};
private Color current = new Color();
public ColorPicker(){
super("$pickcolor");
}
public void show(Color color, Cons<Color> consumer){
show(color, true, consumer);
}
public void show(Color color, boolean alpha, Cons<Color> consumer){
this.current.set(color);
this.cons = consumer;
show();
cont.clear();
cont.pane(t -> {
t.table(Tex.pane, i -> {
i.stack(new Image(Tex.alphaBg), new Image(){{
setColor(current);
update(() -> setColor(current));
}}).size(200f);
}).colspan(2).padBottom(5);
float w = 150f;
t.row();
t.defaults().padBottom(4);
t.add("R").color(Pal.remove);
t.addSlider(0f, 1f, 0.01f, current.r, current::r).width(w);
t.row();
t.add("G").color(Color.lime);
t.addSlider(0f, 1f, 0.01f, current.g, current::g).width(w);
t.row();
t.add("B").color(Color.royal);
t.addSlider(0f, 1f, 0.01f, current.b, current::b).width(w);
t.row();
if(alpha){
t.add("A");
t.addSlider(0f, 1f, 0.01f, current.a, current::a).width(w);
t.row();
}
});
buttons.clear();
addCloseButton();
buttons.addImageTextButton("$ok", Icon.checkSmall, () -> {
cons.get(current);
hide();
});
}
}

View File

@@ -0,0 +1,28 @@
package mindustry.ui.dialogs;
import arc.scene.ui.ScrollPane;
import arc.scene.ui.layout.Table;
import mindustry.ctype.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();
}
}

View File

@@ -0,0 +1,27 @@
package mindustry.ui.dialogs;
import arc.input.*;
import arc.scene.ui.*;
import arc.util.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class ControlsDialog extends KeybindDialog{
public ControlsDialog(){
setFillParent(true);
title.setAlignment(Align.center);
titleTable.row();
titleTable.add(new Image()).growX().height(3f).pad(4f).get().setColor(Pal.accent);
}
@Override
public void addCloseButton(){
buttons.addImageTextButton("$back", Icon.arrowLeftSmall, this::hide).size(230f, 64f);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK)
hide();
});
}
}

View File

@@ -0,0 +1,92 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.maps.*;
import mindustry.ui.*;
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);
maps.marginBottom(55f);
ScrollPane pane = new ScrollPane(maps);
pane.setFadeScrollBars(false);
int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / Scl.scl(200)), 1, 8);
float images = 146f;
int i = 0;
maps.defaults().width(170).fillY().top().pad(4f);
for(Map map : Vars.maps.all()){
if(i % maxwidth == 0){
maps.row();
}
ImageButton image = new ImageButton(new TextureRegion(map.safeTexture()), Styles.cleari);
image.margin(5);
image.top();
Image img = image.getImage();
img.remove();
image.row();
image.table(t -> {
t.left();
for(Gamemode mode : Gamemode.all){
if(mode.valid(map) && Core.atlas.has("icon-mode-" + mode.name())){
t.addImage(Core.atlas.drawable("icon-mode-" + mode.name())).size(16f).pad(4f);
}
}
}).left();
image.row();
image.add(map.name()).pad(1f).growX().wrap().left().get().setEllipsis(true);
image.row();
image.addImage(Tex.whiteui, Pal.gray).growX().pad(3).height(4f);
image.row();
image.add(img).size(images);
BorderImage border = new BorderImage(map.safeTexture(), 3f);
border.setScaling(Scaling.fit);
image.replaceImage(border);
image.clicked(() -> dialog.show(map));
maps.add(image);
i++;
}
if(Vars.maps.all().size == 0){
maps.add("$maps.none").pad(50);
}
cont.add(pane).uniformX();
}
}

View File

@@ -0,0 +1,220 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import mindustry.world.*;
import static mindustry.Vars.*;
public class CustomRulesDialog extends FloatingDialog{
private Table main;
private Rules rules;
private Prov<Rules> resetter;
private LoadoutDialog loadoutDialog;
private FloatingDialog banDialog;
public CustomRulesDialog(){
super("$mode.custom");
loadoutDialog = new LoadoutDialog();
banDialog = new FloatingDialog("$bannedblocks");
banDialog.addCloseButton();
banDialog.shown(this::rebuildBanned);
banDialog.buttons.addImageTextButton("$addall", Icon.arrow16Small, () -> {
rules.bannedBlocks.addAll(content.blocks().select(Block::isBuildable));
rebuildBanned();
}).size(180, 64f);
banDialog.buttons.addImageTextButton("$clear", Icon.trash16Small, () -> {
rules.bannedBlocks.clear();
rebuildBanned();
}).size(180, 64f);
setFillParent(true);
shown(this::setup);
addCloseButton();
}
private void rebuildBanned(){
float previousScroll = banDialog.cont.getChildren().isEmpty() ? 0f : ((ScrollPane)banDialog.cont.getChildren().first()).getScrollY();
banDialog.cont.clear();
banDialog.cont.pane(t -> {
t.margin(10f);
if(rules.bannedBlocks.isEmpty()){
t.add("$empty");
}
Array<Block> array = Array.with(rules.bannedBlocks);
array.sort();
int cols = mobile && Core.graphics.isPortrait() ? 1 : mobile ? 2 : 3;
int i = 0;
for(Block block : array){
t.table(Tex.underline, b -> {
b.left().margin(4f);
b.addImage(block.icon(Cicon.medium)).size(Cicon.medium.size).padRight(3);
b.add(block.localizedName).color(Color.lightGray).padLeft(3).growX().left().wrap();
b.addImageButton(Icon.cancelSmall, Styles.clearPartiali, () -> {
rules.bannedBlocks.remove(block);
rebuildBanned();
}).size(70f).pad(-4f).padLeft(0f);
}).size(300f, 70f).padRight(5);
if(++i % cols == 0){
t.row();
}
}
}).get().setScrollYForce(previousScroll);
banDialog.cont.row();
banDialog.cont.addImageTextButton("$add", Icon.addSmall, () -> {
FloatingDialog dialog = new FloatingDialog("$add");
dialog.cont.pane(t -> {
t.left().margin(14f);
int[] i = {0};
content.blocks().each(b -> !rules.bannedBlocks.contains(b) && b.isBuildable(), b -> {
int cols = mobile && Core.graphics.isPortrait() ? 4 : 12;
t.addImageButton(new TextureRegionDrawable(b.icon(Cicon.medium)), Styles.cleari, () -> {
rules.bannedBlocks.add(b);
rebuildBanned();
dialog.hide();
}).size(60f).get().resizeImage(Cicon.medium.size);
if(++i[0] % cols == 0){
t.row();
}
});
});
dialog.addCloseButton();
dialog.show();
}).size(300f, 64f);
}
public void show(Rules rules, Prov<Rules> resetter){
this.rules = rules;
this.resetter = resetter;
show();
}
void setup(){
cont.clear();
cont.pane(m -> main = m).get().setScrollingDisabled(true, false);
main.margin(10f);
main.addButton("$settings.reset", () -> {
rules = resetter.get();
setup();
requestKeyboard();
requestScroll();
}).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");
number("$rules.respawntime", f -> rules.respawnTime = f * 60f, () -> rules.respawnTime / 60f);
title("$rules.title.resourcesbuilding");
check("$rules.infiniteresources", b -> rules.infiniteResources = b, () -> rules.infiniteResources);
check("$rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions);
number("$rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
number("$rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier);
main.addButton("$configure",
() -> loadoutDialog.show(Blocks.coreShard.itemCapacity, rules.loadout,
() -> {
rules.loadout.clear();
rules.loadout.add(new ItemStack(Items.copper, 100));
}, () -> {}, () -> {}
)).left().width(300f);
main.row();
main.addButton("$bannedblocks", banDialog::show).left().width(300f);
main.row();
title("$rules.title.player");
number("$rules.playerhealthmultiplier", f -> rules.playerHealthMultiplier = f, () -> rules.playerHealthMultiplier);
number("$rules.playerdamagemultiplier", f -> rules.playerDamageMultiplier = f, () -> rules.playerDamageMultiplier);
title("$rules.title.unit");
check("$rules.unitdrops", b -> rules.unitDrops = b, () -> rules.unitDrops, () -> true);
number("$rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier);
number("$rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
number("$rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier);
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));
title("$rules.title.experimental");
check("$rules.lighting", b -> rules.lighting = b, () -> rules.lighting);
main.addButton(b -> {
b.left();
b.table(Tex.pane, in -> {
in.stack(new Image(Tex.alphaBg), new Image(Tex.whiteui){{
update(() -> setColor(rules.ambientLight));
}}).grow();
}).margin(4).size(50f).padRight(10);
b.add("$rules.ambientlight");
}, () -> ui.picker.show(rules.ambientLight, rules.ambientLight::set)).left().width(250f);
main.row();
}
void number(String text, Floatc cons, Floatp prov){
number(text, false, cons, prov, () -> true);
}
void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition){
main.table(t -> {
t.left();
t.add(text).left().padRight(5)
.update(a -> a.setColor(condition.get() ? Color.white : Color.gray));
Vars.platform.addDialog(t.addField((integer ? (int)prov.get() : prov.get()) + "", s -> cons.get(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, Boolc cons, Boolp prov){
check(text, cons, prov, () -> true);
}
void check(String text, Boolc cons, Boolp prov, Boolp 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).padRight(100f).padBottom(-3);
main.row();
main.addImage().color(Pal.accent).height(3f).padRight(100f).padBottom(20);
main.row();
}
}

View File

@@ -0,0 +1,86 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.core.GameState.*;
import mindustry.ctype.*;
import mindustry.ctype.ContentType;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
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().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;
int count = 0;
for(int i = 0; i < array.size; i++){
UnlockableContent unlock = (UnlockableContent)array.get(i);
Image image = unlocked(unlock) ? new Image(unlock.icon(Cicon.medium)) : new Image(Icon.lockedSmall, Pal.gray);
list.add(image).size(8*4).pad(3);
ClickListener listener = new ClickListener();
image.addListener(listener);
if(!Vars.mobile && unlocked(unlock)){
image.addListener(new HandCursorListener());
image.update(() -> image.getColor().lerp(!listener.isOver() ? Color.lightGray : Color.white, 0.4f * Time.delta()));
}
if(unlocked(unlock)){
image.clicked(() -> Vars.ui.content.show(unlock));
image.addListener(new Tooltip(t -> t.background(Tex.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();
}
}

View File

@@ -0,0 +1,319 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.input.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.scene.utils.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.game.EventType.*;
import mindustry.game.Saves.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.SaveIO.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.layout.*;
import mindustry.ui.layout.TreeLayout.*;
import static mindustry.Vars.*;
public class DeployDialog extends FloatingDialog{
private final float nodeSize = Scl.scl(230f);
private ObjectSet<ZoneNode> nodes = new ObjectSet<>();
private ZoneInfoDialog info = new ZoneInfoDialog();
private Rectangle bounds = new Rectangle();
private View view = new View();
public DeployDialog(){
super("", Styles.fullDialog);
treeLayout();
Events.on(ContentReloadEvent.class, e -> treeLayout());
addCloseButton();
buttons.addImageTextButton("$techtree", Icon.tree, () -> ui.tech.show()).size(230f, 64f);
shown(this::setup);
//view input.
addListener(new InputListener(){
@Override
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
return true;
}
@Override
public boolean mouseMoved(InputEvent event, float x, float y){
view.requestScroll();
return super.mouseMoved(event, x, y);
}
});
addListener(new ElementGestureListener(){
@Override
public void zoom(InputEvent event, float initialDistance, float distance){
if(view.lastZoom < 0){
view.lastZoom = view.getScaleX();
}
view.setScale(Mathf.clamp(distance / initialDistance * view.lastZoom, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
view.lastZoom = view.getScaleX();
}
@Override
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){
view.panX += deltaX / view.getScaleX();
view.panY += deltaY / view.getScaleY();
view.moved = true;
view.clamp();
}
});
}
void treeLayout(){
nodes.clear();
ZoneNode root = new ZoneNode(Zones.groundZero, null);
BranchTreeLayout layout = new BranchTreeLayout();
layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f);
layout.gapBetweenNodes = Scl.scl(120f);
layout.layout(root);
bounds.set(layout.getBounds());
bounds.y += nodeSize*0.4f;
}
public void setup(){
platform.updateRPC();
cont.clear();
titleTable.remove();
margin(0f).marginBottom(8);
Stack stack = new Stack();
stack.add(new Image(new Texture("sprites/backgrounds/stars.png"){{
setFilter(TextureFilter.Linear);
}}).setScaling(Scaling.fill));
stack.add(new Image(new Texture("sprites/backgrounds/planet-zero.png"){{
setFilter(TextureFilter.Linear);
}}){{
float[] time = {0};
setColor(Color.fromGray(0.3f));
setScale(1.5f);
update(() -> {
setOrigin(Align.center);
time[0] += Core.graphics.getDeltaTime() * 10f;
setTranslation(Mathf.sin(time[0], 60f, 70f) + view.panX / 30f, Mathf.cos(time[0], 140f, 80f) + (view.panY + 200) / 30f);
});
}}.setScaling(Scaling.fit));
if(control.saves.getZoneSlot() != null){
float size = 250f;
stack.add(new Table(t -> {
SaveSlot slot = control.saves.getZoneSlot();
Stack sub = new Stack();
if(slot.getZone() != null){
sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.fromGray(0.1f)).grow()));
sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> {
TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable();
if(draw.getRegion().getTexture().isDisposed()){
draw.setRegion(slot.getZone().preview);
}
Texture text = slot.previewTexture();
if(draw.getRegion() == slot.getZone().preview && text != null){
draw.setRegion(new TextureRegion(text));
}
}).color(Color.darkGray).grow()));
}
TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName), Styles.squaret, () -> {
control.saves.getZoneSlot().cautiousLoad(() -> {
hide();
ui.loadAnd(() -> {
logic.reset();
net.reset();
try{
slot.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();
}
});
});
});
sub.add(button);
t.add(sub).size(size);
String color = "[lightgray]";
button.defaults().colspan(2);
button.row();
button.add(Core.bundle.format("save", color + slot.getWave()));
button.row();
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
button.row();
t.row();
t.addButton("$abandon", () -> {
ui.showConfirm("$warning", "$abandon.text", () -> {
slot.delete();
setup();
});
}).width(size).height(50f).padTop(3);
}));
}else{
stack.add(view = new View());
}
stack.add(new ItemsDisplay());
cont.add(stack).grow();
//set up direct and indirect children
for(ZoneNode node : nodes){
node.allChildren.clear();
node.allChildren.addAll(node.children);
for(ZoneNode other : nodes){
if(other.zone.requirements.contains(req -> req.zone() == node.zone)){
node.allChildren.add(other);
}
}
}
view.setOrigin(Align.center);
view.setTransform(true);
}
boolean hidden(Zone zone){
return zone.requirements.contains(o -> o.zone() != null && o.zone().locked());
}
void buildButton(Zone zone, Button button){
button.setDisabled(() -> hidden(zone));
button.clicked(() -> {
if(!view.moved){
info.show(zone);
}
});
if(zone.unlocked() && !hidden(zone)){
button.labelWrap(zone.localizedName).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center);
}else{
Cons<Element> flasher = zone.canUnlock() && !hidden(zone) ? e -> e.update(() -> e.getColor().set(Color.white).lerp(Pal.accent, Mathf.absin(3f, 1f))) : e -> {};
flasher.get(button.addImage(Icon.locked).get());
button.row();
flasher.get(button.add("$locked").get());
}
}
class View extends Group{
float panX = 0, panY = -200, lastZoom = -1;
boolean moved = false;
{
for(ZoneNode node : nodes){
Stack stack = new Stack();
Tmp.v1.set(node.width, node.height);
if(node.zone.preview != null){
Tmp.v1.set(Scaling.fit.apply(node.zone.preview.getWidth(), node.zone.preview.getHeight(), node.width, node.height));
}
stack.setSize(Tmp.v1.x, Tmp.v1.y);
stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.fromGray(0.2f)).grow()));
stack.update(() -> stack.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f, Align.center));
Button button = new Button(Styles.squaret);
buildButton(node.zone, button);
stack.add(button);
addChild(stack);
}
released(() -> moved = false);
}
void clamp(){
float pad = nodeSize;
float ox = width/2f, oy = height/2f;
float rx = bounds.x + panX + ox, ry = panY + oy + bounds.y;
float rw = bounds.width, rh = bounds.height;
rx = Mathf.clamp(rx, -rw + pad, Core.graphics.getWidth() - pad);
ry = Mathf.clamp(ry, pad, Core.graphics.getHeight() - rh - pad);
panX = rx - bounds.x - ox;
panY = ry - bounds.y - oy;
}
@Override
public void drawChildren(){
clamp();
float offsetX = panX + width / 2f, offsetY = panY + height / 2f;
for(ZoneNode node : nodes){
for(ZoneNode child : node.allChildren){
Lines.stroke(Scl.scl(4f), node.zone.locked() || child.zone.locked() ? Pal.gray : Pal.gray);
Draw.alpha(parentAlpha);
Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
}
}
Draw.reset();
super.drawChildren();
}
}
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.requirements.size > 0 && other.requirements.first().zone() == zone);
children = new ZoneNode[arr.size];
for(int i = 0; i < children.length; i++){
children[i] = new ZoneNode(arr.get(i), this);
}
}
}
}

View File

@@ -0,0 +1,52 @@
package mindustry.ui.dialogs;
import arc.Core;
import arc.graphics.Color;
import arc.scene.ui.Dialog;
import mindustry.gen.*;
import mindustry.graphics.Pal;
import static mindustry.Vars.*;
public class DiscordDialog extends Dialog{
public DiscordDialog(){
super("");
float h = 70f;
cont.margin(12f);
Color color = Color.valueOf("7289da");
cont.table(t -> {
t.background(Tex.button).margin(0);
t.table(img -> {
img.addImage().height(h - 5).width(40f).color(color);
img.row();
img.addImage().height(5).width(40f).color(color.cpy().mul(0.8f, 0.8f, 0.8f, 1f));
}).expandY();
t.table(i -> {
i.background(Tex.button);
i.addImage(Icon.discord);
}).size(h).left();
t.add("$discord").color(Pal.accent).growX().padLeft(10f);
}).size(440f, h).pad(10f);
buttons.defaults().size(150f, 50);
buttons.addButton("$back", this::hide);
buttons.addButton("$copylink", () -> {
Core.app.setClipboardText(discordURL);
});
buttons.addButton("$openlink", () -> {
if(!Core.net.openURI(discordURL)){
ui.showErrorMessage("$linkfail");
Core.app.setClipboardText(discordURL);
}
});
}
}

View File

@@ -0,0 +1,309 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.files.*;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import arc.util.pooling.*;
import mindustry.gen.*;
import mindustry.ui.*;
import java.util.*;
import static mindustry.Vars.platform;
public class FileChooser extends FloatingDialog{
private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
private static Fi lastDirectory = homeDirectory;
private Table files;
private Fi directory = lastDirectory;
private ScrollPane pane;
private TextField navigation, filefield;
private TextButton ok;
private FileHistory stack = new FileHistory();
private Boolf<Fi> filter;
private Cons<Fi> selectListener;
private boolean open;
public FileChooser(String title, Boolf<Fi> filter, boolean open, Cons<Fi> result){
super(title);
setFillParent(true);
this.open = open;
this.filter = filter;
this.selectListener = result;
onResize(() -> {
cont.clear();
setupWidgets();
});
shown(() -> {
cont.clear();
setupWidgets();
});
}
private void setupWidgets(){
cont.margin(-10);
Table content = new Table();
filefield = new TextField();
filefield.setOnlyFontChars(false);
if(!open) platform.addDialog(filefield);
filefield.setDisabled(open);
ok = new TextButton(open ? "$load" : "$save");
ok.clicked(() -> {
if(ok.isDisabled()) return;
if(selectListener != null)
selectListener.get(directory.child(filefield.getText()));
hide();
});
filefield.changed(() -> {
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
});
filefield.change();
TextButton cancel = new TextButton("$cancel");
cancel.clicked(this::hide);
navigation = new TextField("");
navigation.touchable(Touchable.disabled);
files = new Table();
files.marginRight(10);
files.marginLeft(3);
pane = new ScrollPane(files);
pane.setOverscroll(false, false);
pane.setFadeScrollBars(false);
updateFiles(true);
Table icontable = new Table();
ImageButton up = new ImageButton(Icon.folderParent);
up.clicked(() -> {
directory = directory.parent();
updateFiles(true);
});
ImageButton back = new ImageButton(Icon.arrowLeft);
ImageButton forward = new ImageButton(Icon.arrowRight);
forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back());
forward.setDisabled(() -> !stack.canForward());
back.setDisabled(() -> !stack.canBack());
ImageButton home = new ImageButton(Icon.home);
home.clicked(() -> {
directory = homeDirectory;
lastDirectory = directory;
updateFiles(true);
});
icontable.defaults().height(60).growX().padTop(5).uniform();
icontable.add(home);
icontable.add(back);
icontable.add(forward);
icontable.add(up);
Table fieldcontent = new Table();
fieldcontent.bottom().left().add(new Label("$filename"));
fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f);
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();
content.center().add(pane).colspan(3).grow();
content.row();
if(!open){
content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2);
content.row();
}
content.add(buttons).growX();
cont.add(content).grow();
}
private void updateFileFieldStatus(){
if(!open){
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
}else{
ok.setDisabled(!directory.child(filefield.getText()).exists() || directory.child(filefield.getText()).isDirectory());
}
}
private Fi[] getFileNames(){
Fi[] handles = directory.list(file -> !file.getName().startsWith("."));
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;
}
private void updateFiles(boolean push){
if(push) stack.push(directory);
navigation.setText(directory.toString());
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
layout.setText(Fonts.def, navigation.getText());
if(layout.width < navigation.getWidth()){
navigation.setCursorPosition(0);
}else{
navigation.setCursorPosition(navigation.getText().length());
}
Pools.free(layout);
files.clearChildren();
files.top().left();
Fi[] names = getFileNames();
Image upimage = new Image(Icon.folderParentSmall);
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet);
upbutton.clicked(() -> {
directory = directory.parent();
lastDirectory = directory;
updateFiles(true);
});
upbutton.left().add(upimage).padRight(4f).padLeft(4);
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(Fi file : names){
if(!file.isDirectory() && !filter.get(file)) continue; //skip non-filtered files
String filename = file.name();
TextButton button = new TextButton(filename, Styles.clearTogglet);
button.getLabel().setWrap(false);
button.getLabel().setEllipsis(true);
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.folderSmall : Icon.fileTextSmall);
button.add(image).padRight(4f).padLeft(4);
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("...");
}
}
public class FileHistory{
private Array<Fi> history = new Array<>();
private int index;
public FileHistory(){
}
public void push(Fi 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(Fi file : history){
i++;
if(index == i){
System.out.println("[[" + file.toString() + "]]");
}else{
System.out.println("--" + file.toString() + "--");
}
}
}
}
}

View File

@@ -0,0 +1,67 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.input.*;
import arc.scene.ui.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import static mindustry.Vars.*;
public class FloatingDialog extends Dialog{
private boolean wasPaused;
protected boolean shouldPause;
public FloatingDialog(String title, DialogStyle style){
super(title, style);
setFillParent(true);
this.title.setAlignment(Align.center);
titleTable.row();
titleTable.addImage(Tex.whiteui, Pal.accent)
.growX().height(3f).pad(4f);
hidden(() -> {
if(shouldPause && !state.is(State.menu)){
if(!wasPaused || net.active()){
state.set(State.playing);
}
}
Sounds.back.play();
});
shown(() -> {
if(shouldPause && !state.is(State.menu)){
wasPaused = state.is(State.paused);
state.set(State.paused);
}
});
}
public FloatingDialog(String title){
this(title, Core.scene.getStyle(DialogStyle.class));
}
protected void onResize(Runnable run){
Events.on(ResizeEvent.class, event -> {
if(isShown() && Core.scene.getDialog() == this){
run.run();
updateScrollFocus();
}
});
}
@Override
public void addCloseButton(){
buttons.defaults().size(210f, 64f);
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
Core.app.post(this::hide);
}
});
}
}

View File

@@ -0,0 +1,102 @@
package mindustry.ui.dialogs;
import arc.*;
import mindustry.core.GameState.*;
import mindustry.game.*;
import mindustry.game.EventType.*;
import mindustry.game.Stats.*;
import mindustry.type.*;
import mindustry.ui.Cicon;
import static 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();
if(winner == player.getTeam()){
Events.fire(new WinEvent());
}else{
Events.fire(new LoseEvent());
}
}
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(Cicon.small)).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);
}
}
}
}

View File

@@ -0,0 +1,96 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.graphics.*;
import arc.scene.ui.*;
import arc.util.*;
import mindustry.*;
import mindustry.core.*;
import mindustry.gen.*;
import mindustry.ui.*;
import java.io.*;
import static mindustry.Vars.*;
public class HostDialog extends FloatingDialog{
float w = 300;
public HostDialog(){
super("$hostserver");
addCloseButton();
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(Tex.whiteui, Styles.clearFulli, 40, () -> {
new PaletteDialog().show(color -> {
player.color.set(color);
Core.settings.put("color-0", Color.rgba8888(color));
Core.settings.save();
});
}).size(54f).get();
button.update(() -> button.getStyle().imageUpColor = player.color);
}).width(w).height(70f).pad(4).colspan(3);
cont.row();
cont.add().width(65f);
cont.addButton("$host", () -> {
if(Core.settings.getString("name").trim().isEmpty()){
ui.showInfo("$noname");
return;
}
runHost();
}).width(w).height(70f);
cont.addButton("?", () -> ui.showInfo("$host.info")).size(65f, 70f).padLeft(6f);
shown(() -> {
if(!steam){
Core.app.post(() -> Core.settings.getBoolOnce("hostinfo", () -> ui.showInfo("$host.info")));
}
});
}
public void runHost(){
ui.loadfrag.show("$hosting");
Time.runTask(5f, () -> {
try{
net.host(Vars.port);
player.isAdmin = true;
if(steam){
Core.app.post(() -> Core.settings.getBoolOnce("steampublic2", () -> {
ui.showCustomConfirm("$setting.publichost.name", "$public.confirm", "$yes", "$no", () -> {
Core.settings.putSave("publichost", true);
platform.updateLobby();
}, () -> {
Core.settings.putSave("publichost", false);
platform.updateLobby();
});
}));
}
if(Version.modifier.contains("beta")){
Core.settings.putSave("publichost", false);
platform.updateLobby();
Core.settings.getBoolOnce("betapublic", () -> ui.showInfo("$public.beta"));
}
}catch(IOException e){
ui.showException("$server.error", e);
}
ui.loadfrag.hide();
hide();
});
}
}

View File

@@ -0,0 +1,417 @@
package mindustry.ui.dialogs;
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.struct.*;
import arc.graphics.*;
import arc.input.*;
import arc.math.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import arc.util.serialization.*;
import mindustry.*;
import mindustry.core.*;
import mindustry.gen.*;
import mindustry.net.*;
import mindustry.net.Packets.*;
import mindustry.ui.*;
import static mindustry.Vars.*;
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();
int totalHosts;
public JoinDialog(){
super("$joingame");
loadServers();
if(!steam) buttons.add().width(60f);
buttons.add().growX().width(-1);
addCloseButton();
buttons.add().growX().width(-1);
if(!steam){
buttons.addButton("?", () -> ui.showInfo("$join.info")).size(60f, 64f).width(-1);
}
add = new FloatingDialog("$joingame.title");
add.cont.add("$joingame.ip").padRight(5f).left();
TextField field = add.cont.addField(Core.settings.getString("ip"), text -> {
Core.settings.put("ip", text);
Core.settings.save();
}).size(320f, 54f).get();
platform.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.setIP(Core.settings.getString("ip"));
saveServers();
setupRemote();
refreshRemote();
}
add.hide();
}).disabled(b -> Core.settings.getString("ip").isEmpty() || net.active());
add.shown(() -> {
add.title.setText(renaming != null ? "$server.edit" : "$server.add");
if(renaming != null){
field.setText(renaming.displayIP());
}
});
keyDown(KeyCode.F5, () -> {
refreshLocal();
refreshRemote();
});
shown(() -> {
setup();
refreshLocal();
refreshRemote();
if(!steam){
Core.app.post(() -> Core.settings.getBoolOnce("joininfo", () -> ui.showInfo("$join.info")));
}
});
onResize(this::setup);
}
void setupRemote(){
remote.clear();
for(Server server : servers){
//why are java lambdas this bad
TextButton[] buttons = {null};
TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), Styles.cleart, () -> {
if(!buttons[0].childrenPressed()){
if(server.lastHost != null){
safeConnect(server.ip, server.port, server.lastHost.version);
}else{
connect(server.ip, server.port);
}
}
}).width(targetWidth()).pad(4f).get();
button.getLabel().setWrap(true);
Table inner = new Table();
button.clearChildren();
button.add(inner).growX();
inner.add(button.getLabel()).growX();
inner.addImageButton(Icon.arrowUpSmall, Styles.emptyi, () -> {
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.loadingSmall, Styles.emptyi, () -> {
refreshServer(server);
}).margin(3f).padTop(6f).top().right();
inner.addImageButton(Icon.pencilSmall, Styles.emptyi, () -> {
renaming = server;
add.show();
}).margin(3f).padTop(6f).top().right();
inner.addImageButton(Icon.trash16Small, Styles.emptyi, () -> {
ui.showConfirm("$confirm", "$server.delete", () -> {
servers.removeValue(server, true);
saveServers();
setupRemote();
refreshRemote();
});
}).margin(3f).pad(6).top().right();
button.row();
server.content = button.table(t -> {}).grow().get();
remote.row();
}
}
void refreshRemote(){
for(Server server : servers){
refreshServer(server);
}
}
void refreshServer(Server server){
server.content.clear();
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.add("$host.invalid");
});
}
void setupServer(Server server, Host host){
server.lastHost = host;
server.content.clear();
buildServer(host, server.content);
}
void buildServer(Host host, Table content){
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 if(host.version == Version.build && Version.type.equals(host.versionType)){
//not important
versionString = "";
}else{
versionString = Core.bundle.format("server.version", host.version, host.versionType);
}
content.table(t -> {
t.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true);
t.row();
t.add("[lightgray]" + (Core.bundle.format("players" + (host.players == 1 && host.playerLimit <= 0 ? ".single" : ""), (host.players == 0 ? "[lightgray]" : "[accent]") + host.players + (host.playerLimit > 0 ? "[lightgray]/[accent]" + host.playerLimit : "")+ "[lightgray]"))).left();
t.row();
t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + host.mode.toString()).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);
pane.setFadeScrollBars(false);
pane.setScrollingDisabled(true, false);
setupRemote();
refreshRemote();
cont.clear();
cont.table(t -> {
t.add("$name").padRight(10);
if(!steam){
t.addField(Core.settings.getString("name"), text -> {
player.name = text;
Core.settings.put("name", text);
Core.settings.save();
}).grow().pad(8).get().setMaxLength(maxNameLength);
}else{
t.add(player.name).update(l -> l.setColor(player.color)).grow().pad(8);
}
ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> {
new PaletteDialog().show(color -> {
player.color.set(color);
Core.settings.put("color-0", Color.rgba8888(color));
Core.settings.save();
});
}).size(54f).get();
button.update(() -> button.getStyle().imageUpColor = player.color);
}).width(w).height(70f).pad(4);
cont.row();
cont.add(pane).width(w + 38).pad(0);
cont.row();
cont.addCenteredImageTextButton("$server.add", Icon.add, () -> {
renaming = null;
add.show();
}).marginLeft(6).width(w).height(80f).update(button -> {
float pw = w;
float pad = 0f;
if(pane.getChildren().first().getPrefHeight() > pane.getHeight()){
pw = w + 30;
pad = 6;
}
Cell cell = ((Table)pane.getParent()).getCell(button);
if(!Mathf.equal(cell.minWidth(), pw)){
cell.width(pw);
cell.padLeft(pad);
pane.getParent().invalidateHierarchy();
}
});
}
void refreshLocal(){
totalHosts = 0;
local.clear();
local.background(null);
local.table(Tex.button, t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX();
net.discoverServers(this::addLocalHost, this::finishLocalHosts);
for(String host : defaultServers){
net.pingHost(host, port, this::addLocalHost, e -> {});
}
}
void finishLocalHosts(){
if(totalHosts == 0){
local.clear();
local.background(Tex.button);
local.add("$hosts.none").pad(10f);
local.add().growX();
local.addImageButton(Icon.loading, this::refreshLocal).pad(-12f).padLeft(0).size(70f);
}else{
local.background(null);
}
}
void addLocalHost(Host host){
if(totalHosts == 0){
local.clear();
}
local.background(null);
totalHosts++;
float w = targetWidth();
local.row();
TextButton button = local.addButton("", Styles.cleart, () -> safeConnect(host.address, port, host.version))
.width(w).pad(5f).get();
button.clearChildren();
buildServer(host, button);
}
public void connect(String ip, int port){
if(player.name.trim().isEmpty()){
ui.showInfo("$noname");
return;
}
ui.loadfrag.show("$connecting");
ui.loadfrag.setButton(() -> {
ui.loadfrag.hide();
netClient.disconnectQuietly();
});
Time.runTask(2f, () -> {
logic.reset();
net.reset();
Vars.netClient.beginConnecting();
net.connect(ip, port, () -> {
hide();
add.hide();
});
});
}
void safeConnect(String ip, int port, int version){
if(version != Version.build && Version.build != -1 && version != -1){
ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" +
Core.bundle.format("server.versions", Version.build, version));
}else{
connect(ip, port);
}
}
float targetWidth(){
return Core.graphics.isPortrait() ? 350f : 500f;
}
@SuppressWarnings("unchecked")
private void loadServers(){
servers = Core.settings.getObject("server-list", Array.class, Array::new);
//get servers
Core.net.httpGet(serverJsonURL, result -> {
try{
Jval val = Jval.read(result.getResultAsString());
Core.app.post(() -> {
try{
defaultServers.clear();
val.asArray().each(child -> defaultServers.add(child.getString("address", "<invalid>")));
Log.info("Fetched {0} global servers.", defaultServers.size);
}catch(Throwable ignored){}
});
}catch(Throwable ignored){}
}, t -> {});
}
private void saveServers(){
Core.settings.putObject("server-list", servers);
Core.settings.save();
}
@Serialize
public static class Server{
public String ip;
public int 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(){
}
}
}

View File

@@ -0,0 +1,90 @@
package mindustry.ui.dialogs;
import arc.Core;
import arc.struct.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.Table;
import arc.util.Log;
import arc.util.Strings;
import mindustry.ui.*;
import java.util.Locale;
import static mindustry.Vars.locales;
import static mindustry.Vars.ui;
public class LanguageDialog extends FloatingDialog{
private Locale lastLocale;
private ObjectMap<Locale, String> displayNames = ObjectMap.of(
Locale.TRADITIONAL_CHINESE, "正體中文",
Locale.SIMPLIFIED_CHINESE, "简体中文"
);
public LanguageDialog(){
super("$settings.language");
addCloseButton();
setup();
}
private void setup(){
Table langs = new Table();
langs.marginRight(24f).marginLeft(24f);
ScrollPane pane = new ScrollPane(langs);
pane.setFadeScrollBars(false);
ButtonGroup<TextButton> group = new ButtonGroup<>();
for(Locale loc : locales){
TextButton button = new TextButton(Strings.capitalize(displayNames.get(loc, loc.getDisplayName(loc))), Styles.clearTogglet);
button.clicked(() -> {
if(getLocale().equals(loc)) return;
Core.settings.put("locale", loc.toString());
Core.settings.save();
Log.info("Setting locale: {0}", loc.toString());
ui.showInfo("$language.restart");
});
langs.add(button).group(group).update(t -> t.setChecked(loc.equals(getLocale()))).size(400f, 50f).row();
}
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());
}
}

View File

@@ -0,0 +1,216 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.files.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.game.Saves.*;
import mindustry.gen.*;
import mindustry.io.*;
import mindustry.io.SaveIO.*;
import mindustry.ui.*;
import mindustry.ui.Styles;
import java.io.*;
import static mindustry.Vars.*;
public class LoadDialog extends FloatingDialog{
ScrollPane pane;
Table slots;
public LoadDialog(){
this("$loadgame");
}
public LoadDialog(String title){
super(title);
setup();
shown(() -> {
setup();
Time.runTask(2f, () -> Core.scene.setScrollFocus(pane));
});
addCloseButton();
}
protected void setup(){
cont.clear();
slots = new Table();
pane = new ScrollPane(slots);
pane.setFadeScrollBars(false);
pane.setScrollingDisabled(true, false);
slots.marginRight(24);
Time.runTask(2f, () -> Core.scene.setScrollFocus(pane));
Array<SaveSlot> array = control.saves.getSaveSlots();
array.sort((slot, other) -> -Long.compare(slot.getTimestamp(), other.getTimestamp()));
for(SaveSlot slot : array){
if(slot.isHidden()) continue;
TextButton button = new TextButton("", Styles.cleart);
button.getLabel().remove();
button.clearChildren();
button.defaults().left();
button.table(title -> {
title.add("[accent]" + slot.getName()).left().growX().width(230f).wrap();
title.table(t -> {
t.right();
t.addImageButton(Icon.floppy, Styles.emptytogglei, () -> {
slot.setAutosave(!slot.isAutosave());
}).checked(slot.isAutosave()).right();
t.addImageButton(Icon.trash, Styles.emptyi, () -> {
ui.showConfirm("$confirm", "$save.delete.confirm", () -> {
slot.delete();
setup();
});
}).right();
t.addImageButton(Icon.pencil, Styles.emptyi, () -> {
ui.showTextInput("$save.rename", "$save.rename.text", slot.getName(), text -> {
slot.setName(text);
setup();
});
}).right();
t.addImageButton(Icon.save, Styles.emptyi, () -> {
if(!ios){
platform.showFileChooser(false, saveExtension, file -> {
try{
slot.exportFile(file);
setup();
}catch(IOException e){
ui.showException("save.export.fail", e);
}
});
}else{
try{
Fi file = Core.files.local("save-" + slot.getName() + "." + saveExtension);
slot.exportFile(file);
platform.shareFile(file);
}catch(Exception e){
ui.showException("save.export.fail", e);
}
}
}).right();
}).padRight(-10).growX();
}).growX().colspan(2);
button.row();
String color = "[lightgray]";
TextureRegion def = Core.atlas.find("nomap");
button.left().add(new BorderImage(def, 4f)).update(i -> {
TextureRegionDrawable draw = (TextureRegionDrawable)i.getDrawable();
if(draw.getRegion().getTexture().isDisposed()){
draw.setRegion(def);
}
Texture text = slot.previewTexture();
if(draw.getRegion() == def && text != null){
draw.setRegion(new TextureRegion(text));
}
i.setScaling(Scaling.fit);
}).left().size(160f).padRight(6);
button.table(meta -> {
meta.left().top();
meta.defaults().padBottom(-2).left().width(290f);
meta.row();
meta.labelWrap(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name())));
meta.row();
meta.labelWrap(slot.mode().toString() + " /" + color + " " + Core.bundle.format("save.wave", color + slot.getWave()));
meta.row();
meta.labelWrap(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
meta.row();
meta.labelWrap(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
meta.row();
meta.labelWrap(color + slot.getDate());
meta.row();
}).left().growX().width(250f);
modifyButton(button, slot);
slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).row();
}
cont.add(pane);
addSetup();
}
public void addSetup(){
boolean valids = false;
for(SaveSlot slot : control.saves.getSaveSlots()) if(!slot.isHidden()) valids = true;
if(!valids){
slots.row();
slots.addButton("$save.none", () -> {
}).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f);
}
slots.row();
slots.addImageTextButton("$save.import", Icon.add, () -> {
platform.showFileChooser(true, saveExtension, file -> {
if(SaveIO.isSaveValid(file)){
try{
control.saves.importSave(file);
setup();
}catch(IOException e){
e.printStackTrace();
ui.showException("$save.import.fail", e);
}
}else{
ui.showErrorMessage("$save.import.invalid");
}
});
}).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);
}
public void runLoadSave(SaveSlot slot){
slot.cautiousLoad(() -> {
ui.loadAnd(() -> {
hide();
ui.paused.hide();
try{
net.reset();
slot.load();
state.rules.editor = false;
state.rules.zone = null;
state.set(State.playing);
}catch(SaveException e){
Log.err(e);
state.set(State.menu);
logic.reset();
ui.showErrorMessage("$save.corrupted");
}
});
});
}
public void modifyButton(TextButton button, SaveSlot slot){
button.clicked(() -> {
if(!button.childrenPressed()){
runLoadSave(slot);
}
});
}
}

View File

@@ -0,0 +1,127 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.input.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import static mindustry.Vars.*;
public class LoadoutDialog extends FloatingDialog{
private Runnable hider;
private Runnable resetter;
private Runnable updater;
private Array<ItemStack> stacks = new Array<>();
private Array<ItemStack> originalStacks = new Array<>();
private Table items;
private int capacity;
public LoadoutDialog(){
super("$configure");
setFillParent(true);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
Core.app.post(this::hide);
}
});
cont.pane(t -> items = t.margin(10f)).left();
shown(this::setup);
hidden(() -> {
originalStacks.selectFrom(stacks, s -> s.amount > 0);
updater.run();
if(hider != null){
hider.run();
}
});
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
buttons.addImageTextButton("$settings.reset", Icon.refreshSmall, () -> {
resetter.run();
reseed();
updater.run();
setup();
}).size(210f, 64f);
}
public void show(int capacity, Array<ItemStack> stacks, Runnable reseter, Runnable updater, Runnable hider){
this.originalStacks = stacks;
reseed();
this.resetter = reseter;
this.updater = updater;
this.capacity = capacity;
this.hider = hider;
//this.filter = filter;
show();
}
void setup(){
items.clearChildren();
items.left();
float bsize = 40f;
int i = 0;
for(ItemStack stack : stacks){
items.table(Tex.pane, t -> {
t.margin(4).marginRight(8).left();
t.addButton("-", Styles.cleart, () -> {
stack.amount = Math.max(stack.amount - step(stack.amount), 0);
updater.run();
}).size(bsize);
t.addButton("+", Styles.cleart, () -> {
stack.amount = Math.min(stack.amount + step(stack.amount), capacity);
updater.run();
}).size(bsize);
t.addImageButton(Icon.pencilSmaller, Styles.cleari, () -> ui.showTextInput("$configure", stack.item.localizedName, 10, stack.amount + "", true, str -> {
if(Strings.canParsePostiveInt(str)){
int amount = Strings.parseInt(str);
if(amount >= 0 && amount <= capacity){
stack.amount = amount;
updater.run();
return;
}
}
ui.showInfo(Core.bundle.format("configure.invalid", capacity));
})).size(bsize);
t.addImage(stack.item.icon(Cicon.small)).size(8 * 3).padRight(4).padLeft(4);
t.label(() -> stack.amount + "").left().width(90f);
}).pad(2).left().fillX();
if(++i % 2 == 0 || (mobile && Core.graphics.isPortrait())){
items.row();
}
}
}
private void reseed(){
this.stacks = originalStacks.map(ItemStack::copy);
this.stacks.addAll(content.items().select(i -> i.type == ItemType.material &&
!stacks.contains(stack -> stack.item == i)).map(i -> new ItemStack(i, 0)));
this.stacks.sort(Structs.comparingInt(s -> s.item.id));
}
private int step(int amount){
if(amount < 1000){
return 100;
}else if(amount < 2000){
return 200;
}else if(amount < 5000){
return 500;
}else{
return 1000;
}
}
}

View File

@@ -0,0 +1,110 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.maps.*;
import mindustry.ui.*;
import static mindustry.Vars.*;
public class MapPlayDialog extends FloatingDialog{
CustomRulesDialog dialog = new CustomRulesDialog();
Rules rules;
@NonNull
Gamemode selectedGamemode = Gamemode.survival;
Map lastMap;
public MapPlayDialog(){
super("");
setFillParent(false);
onResize(() -> {
if(lastMap != null){
Rules rules = this.rules;
show(lastMap);
this.rules = rules;
}
});
}
public void show(Map map){
this.lastMap = map;
title.setText(map.name());
cont.clearChildren();
//reset to any valid mode after switching to attack (one must exist)
if(!selectedGamemode.valid(map)){
selectedGamemode = Structs.find(Gamemode.all, m -> m.valid(map));
if(selectedGamemode == null){
selectedGamemode = Gamemode.survival;
}
}
rules = map.applyRules(selectedGamemode);
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;
modes.addButton(mode.toString(), Styles.togglet, () -> {
selectedGamemode = mode;
rules = map.applyRules(mode);
}).update(b -> b.setChecked(selectedGamemode == mode)).size(140f, 54f).disabled(!mode.valid(map));
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.toolsSmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230);
cont.row();
cont.add(new BorderImage(map.safeTexture(), 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit);
//only maps with survival are valid for high scores
if(Gamemode.survival.valid(map)){
cont.row();
cont.label((() -> Core.bundle.format("level.highscore", map.getHightScore()))).pad(3f);
}
buttons.clearChildren();
addCloseButton();
buttons.addImageTextButton("$play", Icon.play, () -> {
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();
}
}

View File

@@ -0,0 +1,220 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.graphics.*;
import arc.input.*;
import arc.math.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.*;
import mindustry.maps.*;
import mindustry.ui.*;
import static mindustry.Vars.*;
public class MapsDialog extends FloatingDialog{
private FloatingDialog dialog;
public MapsDialog(){
super("$maps");
buttons.remove();
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
Core.app.post(this::hide);
}
});
shown(this::setup);
onResize(() -> {
if(dialog != null){
dialog.hide();
}
setup();
});
}
void setup(){
buttons.clearChildren();
if(Core.graphics.isPortrait()){
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f*2f, 64f).colspan(2);
buttons.row();
}else{
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
}
buttons.addImageTextButton("$editor.newmap", Icon.add, () -> {
ui.showTextInput("$editor.newmap", "$name", "", text -> {
Runnable show = () -> ui.loadAnd(() -> {
hide();
ui.editor.show();
ui.editor.editor.getTags().put("name", text);
Events.fire(new MapMakeEvent());
});
if(maps.byName(text) != null){
ui.showErrorMessage("$editor.exists");
}else{
show.run();
}
});
}).size(210f, 64f);
buttons.addImageTextButton("$editor.importmap", Icon.load, () -> {
platform.showFileChooser(true, mapExtension, file -> {
ui.loadAnd(() -> {
maps.tryCatchMapError(() -> {
if(MapIO.isImage(file)){
ui.showErrorMessage("$editor.errorimage");
return;
}
Map map = MapIO.createMap(file, true);
//when you attempt to import a save, it will have no name, so generate one
String name = map.tags.getOr("name", () -> {
String result = "unknown";
int number = 0;
while(maps.byName(result + number++) != null);
return result + number;
});
//this will never actually get called, but it remains just in case
if(name == null){
ui.showErrorMessage("$editor.errorname");
return;
}
Map conflict = 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", () -> {
maps.tryCatchMapError(() -> {
maps.removeMap(conflict);
maps.importMap(map.file);
setup();
});
});
}else{
maps.importMap(map.file);
setup();
}
});
});
});
}).size(210f, 64f);
cont.clear();
Table maps = new Table();
maps.marginRight(24);
ScrollPane pane = new ScrollPane(maps);
pane.setFadeScrollBars(false);
int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / Scl.scl(230)), 1, 8);
float mapsize = 200f;
int i = 0;
for(Map map : Vars.maps.all()){
if(i % maxwidth == 0){
maps.row();
}
TextButton button = maps.addButton("", Styles.cleart, () -> 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().growX().pad(4).color(Pal.gray);
button.row();
button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f);
button.row();
button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : map.mod != null ? "[lightgray]" + map.mod.meta.displayName() : "$builtin").color(Color.gray).padTop(3);
i++;
}
if(Vars.maps.all().size == 0){
maps.add("$maps.none");
}
cont.add(buttons).growX();
cont.row();
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.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize);
table.table(Styles.black, 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.custom && map.author().isEmpty() ? "Anuke" : 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.loadMapSmall, () -> {
try{
Vars.ui.editor.beginEditMap(map.file);
dialog.hide();
hide();
}catch(Exception e){
e.printStackTrace();
ui.showErrorMessage("$error.mapnotfound");
}
}).fillX().height(54f).marginLeft(10);
table.addImageTextButton(map.workshop && steam ? "$view.workshop" : "$delete", map.workshop && steam ? Icon.linkSmall : Icon.trash16Small, () -> {
if(map.workshop && steam){
platform.viewListing(map);
}else{
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> {
maps.removeMap(map);
dialog.hide();
setup();
});
}
}).fillX().height(54f).marginLeft(10).disabled(!map.workshop && !map.custom);
dialog.show();
}
}

View File

@@ -0,0 +1,70 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.input.*;
import arc.scene.event.*;
import arc.scene.ui.layout.*;
import mindustry.gen.*;
import static mindustry.Vars.renderer;
public class MinimapDialog extends FloatingDialog{
public MinimapDialog(){
super("$minimap");
setFillParent(true);
shown(this::setup);
addCloseButton();
shouldPause = true;
titleTable.remove();
onResize(this::setup);
}
void setup(){
cont.clear();
cont.table(Tex.pane,t -> {
t.addRect((x, y, width, height) -> {
if(renderer.minimap.getRegion() == null) return;
Draw.color(Color.white);
Draw.alpha(parentAlpha);
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(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f) / Scl.scl(1f)).padTop(-20f);
cont.addListener(new InputListener(){
@Override
public boolean scrolled(InputEvent event, float x, float y, float amountx, float amounty){
renderer.minimap.zoomBy(amounty);
return true;
}
});
cont.addListener(new ElementGestureListener(){
float lzoom = -1f;
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
lzoom = renderer.minimap.getZoom();
}
@Override
public void zoom(InputEvent event, float initialDistance, float distance){
if(lzoom < 0){
lzoom = renderer.minimap.getZoom();
}
renderer.minimap.setZoom(initialDistance / distance * lzoom);
}
});
Core.app.post(() -> Core.scene.setScrollFocus(cont));
}
}

View File

@@ -0,0 +1,195 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.Net.*;
import arc.files.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.mod.Mods.*;
import mindustry.ui.*;
import java.io.*;
import static mindustry.Vars.*;
public class ModsDialog extends FloatingDialog{
public ModsDialog(){
super("$mods");
addCloseButton();
buttons.addImageTextButton(mobile ? "$mods.report" : "$mods.openfolder", Icon.link,
() -> {
if(mobile){
Core.net.openURI(reportIssueURL);
}else{
Core.net.openFolder(modDirectory.absolutePath());
}
})
.size(250f, 64f);
buttons.row();
buttons.addImageTextButton("$mods.guide", Icon.wiki,
() -> Core.net.openURI(modGuideURL))
.size(210, 64f);
buttons.addImageTextButton("$mod.import.github", Icon.github, () -> {
ui.showTextInput("$mod.import.github", "", 64, "Anuken/ExampleMod", text -> {
ui.loadfrag.show();
Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> {
Core.net.httpGet(loc.getHeader("Location"), result -> {
if(result.getStatus() != HttpStatus.OK){
ui.showErrorMessage(Core.bundle.format("connectfail", result.getStatus()));
ui.loadfrag.hide();
}else{
try{
Fi file = tmpDirectory.child(text.replace("/", "") + ".zip");
Streams.copyStream(result.getResultAsStream(), file.write(false));
mods.importMod(file);
file.delete();
Core.app.post(() -> {
try{
mods.reloadContent();
setup();
ui.loadfrag.hide();
}catch(Throwable e){
ui.showException(e);
}
});
}catch(Throwable e){
modError(e);
}
}
}, t -> Core.app.post(() -> modError(t)));
}, t -> Core.app.post(() -> modError(t)));
});
}).size(250f, 64f);
shown(this::setup);
hidden(() -> {
if(mods.requiresReload()){
ui.loadAnd("$reloading", () -> {
mods.eachEnabled(mod -> {
if(mod.hasUnmetDependencies()){
ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", ")));
}
});
mods.reloadContent();
});
}
});
shown(() -> Core.app.post(() -> {
Core.settings.getBoolOnce("modsalpha", () -> {
ui.showText("$mods", "$mods.alphainfo");
});
}));
}
void modError(Throwable error){
ui.loadfrag.hide();
if(Strings.getCauses(error).contains(t -> t.getMessage() != null && (t.getMessage().contains("SSL") || t.getMessage().contains("protocol")))){
ui.showErrorMessage("$feature.unsupported");
}else{
ui.showException(error);
}
}
void setup(){
cont.clear();
cont.defaults().width(mobile ? 500 : 560f).pad(4);
cont.add("$mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center);
cont.row();
if(!mods.list().isEmpty()){
cont.pane(table -> {
table.margin(10f).top();
boolean anyDisabled = false;
for(LoadedMod mod : mods.list()){
if(!mod.enabled() && !anyDisabled && mods.list().size > 0){
anyDisabled = true;
table.row();
table.addImage().growX().height(4f).pad(6f).color(Pal.gray);
table.row();
}
table.table(Styles.black6, t -> {
t.defaults().pad(2).left().top();
t.margin(14f).left();
t.table(title -> {
title.left();
title.add("[accent]" + mod.meta.displayName() + "[lightgray] v" + mod.meta.version + (mod.enabled() ? "" : "\n" + Core.bundle.get("mod.disabled") + "")).width(200f).wrap();
title.add().growX();
title.addImageTextButton(mod.enabled() ? "$mod.disable" : "$mod.enable", mod.enabled() ? Icon.arrowDownSmall : Icon.arrowUpSmall, Styles.cleart, () -> {
mods.setEnabled(mod, !mod.enabled());
setup();
}).height(50f).margin(8f).width(130f).disabled(!mod.isSupported());
if(steam && !mod.hasSteamID()){
title.addImageButton(Icon.loadMapSmall, Styles.cleari, () -> {
platform.publish(mod);
}).size(50f);
}
title.addImageButton(mod.hasSteamID() ? Icon.linkSmall : Icon.trash16Small, Styles.cleari, () -> {
if(!mod.hasSteamID()){
ui.showConfirm("$confirm", "$mod.remove.confirm", () -> {
mods.removeMod(mod);
setup();
});
}else{
platform.viewListing(mod);
}
}).size(50f);
}).growX().left().padTop(-14f).padRight(-14f);
t.row();
if(mod.meta.author != null){
t.add(Core.bundle.format("mod.author", mod.meta.author));
t.row();
}
if(mod.meta.description != null){
t.labelWrap("[lightgray]" + mod.meta.description).growX();
t.row();
}
if(!mod.isSupported()){
t.labelWrap(Core.bundle.format("mod.requiresversion", mod.meta.minGameVersion)).growX();
t.row();
}else if(mod.hasUnmetDependencies()){
t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX();
t.row();
}else if(mod.hasContentErrors()){
t.labelWrap("$mod.erroredcontent").growX();
t.row();
}
}).width(mobile ? 430f : 500f);
table.row();
}
});
}else{
cont.table(Styles.black6, t -> t.add("$mods.none")).height(80f);
}
cont.row();
cont.addImageTextButton("$mod.import", Icon.add, () -> {
platform.showFileChooser(true, "zip", file -> {
try{
mods.importMod(file);
setup();
}catch(IOException e){
ui.showException(e);
e.printStackTrace();
}
});
}).margin(12f).width(400f);
}
}

View File

@@ -0,0 +1,51 @@
package mindustry.ui.dialogs;
import arc.func.*;
import arc.graphics.*;
import arc.input.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import mindustry.gen.*;
import mindustry.ui.*;
import static mindustry.Vars.*;
public class PaletteDialog extends Dialog{
private Cons<Color> cons;
public PaletteDialog(){
super("");
build();
}
private void build(){
Table table = new Table();
cont.add(table);
for(int i = 0; i < playerColors.length; i++){
Color color = playerColors[i];
ImageButton button = table.addImageButton(Tex.whiteui, Styles.clearTogglei, 34, () -> {
cons.get(color);
hide();
}).size(48).get();
button.setChecked(player.color.equals(color));
button.getStyle().imageUpColor = color;
if(i % 4 == 3){
table.row();
}
}
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK)
hide();
});
}
public void show(Cons<Color> cons){
this.cons = cons;
show();
}
}

View File

@@ -0,0 +1,134 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.input.*;
import mindustry.core.GameState.*;
import mindustry.gen.*;
import static mindustry.Vars.*;
public class PausedDialog extends FloatingDialog{
private SaveDialog save = new SaveDialog();
private LoadDialog load = new LoadDialog();
private boolean wasClient = false;
public PausedDialog(){
super("$menu");
shouldPause = true;
shown(this::rebuild);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
hide();
}
});
}
void rebuild(){
cont.clear();
update(() -> {
if(state.is(State.menu) && isShown()){
hide();
}
});
if(!mobile){
float dw = 210f;
cont.defaults().width(dw).height(50).pad(5f);
cont.addButton("$back", this::hide).colspan(2).width(dw * 2 + 20f);
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(!state.rules.tutorial){
if(!world.isZone() && !state.isEditor()){
cont.row();
cont.addButton("$savegame", save::show);
cont.addButton("$loadgame", load::show).disabled(b -> net.active());
}
cont.row();
cont.addButton("$hostserver", () -> {
if(net.server() && steam){
platform.inviteFriends();
}else{
if(steam){
ui.host.runHost();
}else{
ui.host.show();
}
}
}).disabled(b -> !((steam && net.server()) || !net.active())).colspan(2).width(dw * 2 + 20f).update(e -> e.setText(net.server() && steam ? "$invitefriends" : "$hostserver"));
}
cont.row();
cont.addButton("$quit", this::showQuitConfirm).colspan(2).width(dw + 10f).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "$save.quit" : "$quit"));
}else{
cont.defaults().size(130f).pad(5);
cont.addRowImageTextButton("$back", Icon.play2, this::hide);
cont.addRowImageTextButton("$settings", Icon.tools, ui.settings::show);
if(!world.isZone() && !state.isEditor()){
cont.addRowImageTextButton("$save", Icon.save, save::show);
cont.row();
cont.addRowImageTextButton("$load", Icon.load, load::show).disabled(b -> net.active());
}else{
cont.row();
}
cont.addRowImageTextButton("$hostserver.mobile", Icon.host, ui.host::show).disabled(b -> net.active());
cont.addRowImageTextButton("$quit", Icon.quit, this::showQuitConfirm).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "$save.quit" : "$quit"));
}
}
void showQuitConfirm(){
ui.showConfirm("$confirm", state.rules.tutorial ? "$quit.confirm.tutorial" : "$quit.confirm", () -> {
if(state.rules.tutorial){
Core.settings.put("playedtutorial", true);
Core.settings.save();
}
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.rules.tutorial || wasClient){
state.set(State.menu);
logic.reset();
return;
}
ui.loadAnd("$saveload", () -> {
try{
control.saves.getCurrent().save();
}catch(Throwable e){
e.printStackTrace();
ui.showException("[accent]" + Core.bundle.get("savefail"), e);
}
state.set(State.menu);
logic.reset();
});
}
}

View File

@@ -0,0 +1,62 @@
package mindustry.ui.dialogs;
import arc.Core;
import arc.scene.ui.TextButton;
import arc.util.Time;
import mindustry.core.GameState.State;
import mindustry.game.Saves.SaveSlot;
import mindustry.gen.*;
import static mindustry.Vars.*;
public class SaveDialog extends LoadDialog{
public SaveDialog(){
super("$savegame");
update(() -> {
if(state.is(State.menu) && isShown()){
hide();
}
});
}
public void addSetup(){
slots.row();
slots.addImageTextButton("$save.new", Icon.add, () ->
ui.showTextInput("$save", "$save.newslot", 30, "", text -> {
ui.loadAnd("$saving", () -> {
control.saves.addSave(text);
Core.app.post(() -> Core.app.post(this::setup));
});
})
).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);
}
@Override
public void modifyButton(TextButton button, SaveSlot slot){
button.clicked(() -> {
if(button.childrenPressed()) return;
ui.showConfirm("$overwrite", "$save.overwrite", () -> save(slot));
});
}
void save(SaveSlot slot){
ui.loadfrag.show("$saveload");
Time.runTask(5f, () -> {
hide();
ui.loadfrag.hide();
try{
slot.save();
}catch(Throwable e){
e.printStackTrace();
ui.showException("[accent]" + Core.bundle.get("savefail"), e);
}
});
}
}

View File

@@ -0,0 +1,325 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.graphics.Texture.*;
import arc.graphics.g2d.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.ImageButton.*;
import arc.scene.ui.TextButton.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import static mindustry.Vars.*;
public class SchematicsDialog extends FloatingDialog{
private SchematicInfoDialog info = new SchematicInfoDialog();
private String search = "";
public SchematicsDialog(){
super("$schematics");
Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> {
((Texture)t).setWrap(TextureWrap.Repeat);
};
shouldPause = true;
addCloseButton();
buttons.addImageTextButton("$schematic.import", Icon.loadMapSmall, this::showImport);
shown(this::setup);
onResize(this::setup);
}
void setup(){
search = "";
Runnable[] rebuildPane = {null};
cont.top();
cont.clear();
cont.table(s -> {
s.left();
s.addImage(Icon.zoom);
s.addField(search, res -> {
search = res;
rebuildPane[0].run();
}).growX();
}).fillX().padBottom(4);
cont.row();
cont.pane(t -> {
t.top();
t.margin(20f);
rebuildPane[0] = () -> {
t.clear();
int i = 0;
if(!schematics.all().contains(s -> search.isEmpty() || s.name().toLowerCase().contains(search.toLowerCase()))){
t.add("$none");
}
for(Schematic s : schematics.all()){
if(!search.isEmpty() && !s.name().toLowerCase().contains(search.toLowerCase())) continue;
Button[] sel = {null};
sel[0] = t.addButton(b -> {
b.top();
b.margin(0f);
b.table(buttons -> {
buttons.left();
buttons.defaults().size(50f);
ImageButtonStyle style = Styles.clearPartiali;
buttons.addImageButton(Icon.infoSmall, style, () -> {
showInfo(s);
});
buttons.addImageButton(Icon.loadMapSmall, style, () -> {
showExport(s);
});
buttons.addImageButton(Icon.pencilSmall, style, () -> {
ui.showTextInput("$schematic.rename", "$name", s.name(), res -> {
s.tags.put("name", res);
s.save();
rebuildPane[0].run();
});
});
if(s.hasSteamID()){
buttons.addImageButton(Icon.linkSmall, style, () -> platform.viewListing(s));
}else{
buttons.addImageButton(Icon.trash16Small, style, () -> {
if(s.mod != null){
ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.displayName()));
}else{
ui.showConfirm("$confirm", "$schematic.delete.confirm", () -> {
schematics.remove(s);
rebuildPane[0].run();
});
}
});
}
}).growX().height(50f);
b.row();
b.stack(new SchematicImage(s).setScaling(Scaling.fit), new Table(n -> {
n.top();
n.table(Styles.black3, c -> {
Label label = c.add(s.name()).style(Styles.outlineLabel).color(Color.white).top().growX().maxWidth(200f - 8f).get();
label.setEllipsis(true);
label.setAlignment(Align.center);
}).growX().margin(1).pad(4).maxWidth(Scl.scl(200f - 8f)).padBottom(0);
})).size(200f);
}, () -> {
if(sel[0].childrenPressed()) return;
if(state.is(State.menu)){
showInfo(s);
}else{
control.input.useSchematic(s);
hide();
}
}).pad(4).style(Styles.cleari).get();
sel[0].getStyle().up = Tex.pane;
if(++i % (mobile ? Core.graphics.isPortrait() ? 2 : 3 : 4) == 0){
t.row();
}
}
};
rebuildPane[0].run();
}).get().setScrollingDisabled(true, false);
}
public void showInfo(Schematic schematic){
info.show(schematic);
}
public void showImport(){
FloatingDialog dialog = new FloatingDialog("$editor.export");
dialog.cont.pane(p -> {
p.margin(10f);
p.table(Tex.button, t -> {
TextButtonStyle style = Styles.cleart;
t.defaults().size(280f, 60f).left();
t.row();
t.addImageTextButton("$schematic.copy.import", Icon.copySmall, style, () -> {
dialog.hide();
try{
Schematic s = Schematics.readBase64(Core.app.getClipboardText());
s.removeSteamID();
schematics.add(s);
setup();
ui.showInfoFade("$schematic.saved");
showInfo(s);
}catch(Exception e){
ui.showException(e);
}
}).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart));
t.row();
t.addImageTextButton("$schematic.importfile", Icon.saveMapSmall, style, () -> platform.showFileChooser(true, schematicExtension, file -> {
dialog.hide();
try{
Schematic s = Schematics.read(file);
s.removeSteamID();
schematics.add(s);
setup();
showInfo(s);
}catch(Exception e){
ui.showException(e);
}
})).marginLeft(12f);
t.row();
if(steam){
t.addImageTextButton("$schematic.browseworkshop", Icon.wikiSmall, style, () -> {
dialog.hide();
platform.openWorkshop();
}).marginLeft(12f);
}
});
});
dialog.addCloseButton();
dialog.show();
}
public void showExport(Schematic s){
FloatingDialog dialog = new FloatingDialog("$editor.export");
dialog.cont.pane(p -> {
p.margin(10f);
p.table(Tex.button, t -> {
TextButtonStyle style = Styles.cleart;
t.defaults().size(280f, 60f).left();
if(steam && !s.hasSteamID()){
t.addImageTextButton("$schematic.shareworkshop", Icon.wikiSmall, style,
() -> platform.publish(s)).marginLeft(12f);
t.row();
dialog.hide();
}
t.addImageTextButton("$schematic.copy", Icon.copySmall, style, () -> {
dialog.hide();
ui.showInfoFade("$copied");
Core.app.setClipboardText(schematics.writeBase64(s));
}).marginLeft(12f);
t.row();
t.addImageTextButton("$schematic.exportfile", Icon.saveMapSmall, style, () -> platform.showFileChooser(false, schematicExtension, file -> {
dialog.hide();
try{
Schematics.write(s, file);
}catch(Exception e){
ui.showException(e);
}
})).marginLeft(12f);
});
});
dialog.addCloseButton();
dialog.show();
}
public static class SchematicImage extends Image{
public float scaling = 16f;
public float thickness = 4f;
public Color borderColor = Pal.gray;
private Schematic schematic;
boolean set;
public SchematicImage(Schematic s){
super(Tex.clear);
setScaling(Scaling.fit);
schematic = s;
if(schematics.hasPreview(s)){
setPreview();
set = true;
}
}
@Override
public void draw(){
boolean checked = getParent().getParent() instanceof Button
&& ((Button)getParent().getParent()).isOver();
boolean wasSet = set;
if(!set){
Core.app.post(this::setPreview);
set = true;
}
Texture background = Core.assets.get("sprites/schematic-background.png", Texture.class);
TextureRegion region = Draw.wrap(background);
float xr = width / scaling;
float yr = height / scaling;
region.setU2(xr);
region.setV2(yr);
Draw.color();
Draw.alpha(parentAlpha);
Draw.rect(region, x + width/2f, y + height/2f, width, height);
if(wasSet){
super.draw();
}else{
Draw.rect(Icon.loading.getRegion(), x + width/2f, y + height/2f, width/4f, height/4f);
}
Draw.color(checked ? Pal.accent : borderColor);
Draw.alpha(parentAlpha);
Lines.stroke(Scl.scl(thickness));
Lines.rect(x, y, width, height);
Draw.reset();
}
private void setPreview(){
TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(schematics.getPreview(schematic)));
setDrawable(draw);
setScaling(Scaling.fit);
}
}
public static class SchematicInfoDialog extends FloatingDialog{
SchematicInfoDialog(){
super("");
setFillParent(true);
addCloseButton();
}
public void show(Schematic schem){
cont.clear();
title.setText("[[" + Core.bundle.get("schematic") + "] " +schem.name());
cont.add(Core.bundle.format("schematic.info", schem.width, schem.height, schem.tiles.size)).color(Color.lightGray);
cont.row();
cont.add(new SchematicImage(schem)).maxSize(800f);
cont.row();
Array<ItemStack> arr = schem.requirements();
cont.table(r -> {
int i = 0;
for(ItemStack s : arr){
r.addImage(s.item.icon(Cicon.small)).left();
r.add(s.amount + "").padLeft(2).left().color(Color.lightGray).padRight(4);
if(++i % 4 == 0){
r.row();
}
}
});
show();
}
}
}

View File

@@ -0,0 +1,376 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.files.*;
import arc.graphics.*;
import arc.graphics.Texture.*;
import arc.input.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.SettingsDialog.SettingsTable.*;
import arc.scene.ui.TextButton.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.core.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.*;
import mindustry.ui.*;
import static arc.Core.bundle;
import static mindustry.Vars.*;
public class SettingsMenuDialog extends SettingsDialog{
private SettingsTable graphics;
private SettingsTable game;
private SettingsTable sound;
private Table prefs;
private Table menu;
private FloatingDialog dataDialog;
private boolean wasPaused;
public SettingsMenuDialog(){
hidden(() -> {
Sounds.back.play();
if(!state.is(State.menu)){
if(!wasPaused || net.active())
state.set(State.playing);
}
});
shown(() -> {
back();
if(!state.is(State.menu)){
wasPaused = state.is(State.paused);
state.set(State.paused);
}
rebuildMenu();
});
setFillParent(true);
title.setAlignment(Align.center);
titleTable.row();
titleTable.add(new Image()).growX().height(3f).pad(4f).get().setColor(Pal.accent);
cont.clearChildren();
cont.remove();
buttons.remove();
menu = new Table(Tex.button);
game = new SettingsTable();
graphics = new SettingsTable();
sound = new SettingsTable();
prefs = new Table();
prefs.top();
prefs.margin(14f);
rebuildMenu();
prefs.clearChildren();
prefs.add(menu);
dataDialog = new FloatingDialog("$settings.data");
dataDialog.addCloseButton();
dataDialog.cont.table(Tex.button, t -> {
t.defaults().size(240f, 60f).left();
TextButtonStyle style = Styles.cleart;
t.addButton("$settings.cleardata", style, () -> 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();
for(Fi file : dataDirectory.list()){
file.deleteDirectory();
}
Core.app.exit();
}));
t.row();
t.addButton("$data.export", style, () -> {
if(ios){
Fi file = Core.files.local("mindustry-data-export.zip");
try{
data.exportData(file);
}catch(Exception e){
ui.showException(e);
}
platform.shareFile(file);
}else{
platform.showFileChooser(false, "zip", file -> {
try{
data.exportData(file);
ui.showInfo("$data.exported");
}catch(Exception e){
e.printStackTrace();
ui.showException(e);
}
});
}
});
t.row();
t.addButton("$data.import", style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> {
try{
data.importData(file);
Core.app.exit();
}catch(IllegalArgumentException e){
ui.showErrorMessage("$data.invalid");
}catch(Exception e){
e.printStackTrace();
if(e.getMessage() == null || !e.getMessage().contains("too short")){
ui.showException(e);
}else{
ui.showErrorMessage("$data.invalid");
}
}
})));
});
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;
}
return super.touchDown(event, x, y, pointer, button);
}
@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);
row();
add(pane).grow().top();
row();
add(buttons).fillX();
addSettings();
}
void rebuildMenu(){
menu.clearChildren();
TextButtonStyle style = Styles.cleart;
menu.defaults().size(300f, 60f);
menu.addButton("$settings.game", style, () -> visible(0));
menu.row();
menu.addButton("$settings.graphics", style, () -> visible(1));
menu.row();
menu.addButton("$settings.sound", style, () -> visible(2));
menu.row();
menu.addButton("$settings.language", style, ui.language::show);
if(!mobile || Core.settings.getBool("keyboard")){
menu.row();
menu.addButton("$settings.controls", style, ui.controls::show);
}
menu.row();
menu.addButton("$settings.data", style, () -> dataDialog.show());
}
void addSettings(){
sound.sliderPref("musicvol", bundle.get("setting.musicvol.name", "Music Volume"), 100, 0, 100, 1, i -> i + "%");
sound.sliderPref("sfxvol", bundle.get("setting.sfxvol.name", "SFX Volume"), 100, 0, 100, 1, i -> i + "%");
sound.sliderPref("ambientvol", bundle.get("setting.ambientvol.name", "Ambient Volume"), 100, 0, 100, 1, i -> i + "%");
game.screenshakePref();
if(mobile){
game.checkPref("autotarget", true);
game.checkPref("keyboard", false, val -> control.setInput(val ? new DesktopInput() : new MobileInput()));
if(Core.settings.getBool("keyboard")){
control.setInput(new DesktopInput());
}
}
//the issue with touchscreen support on desktop is that:
//1) I can't test it
//2) the SDL backend doesn't support multitouch
/*else{
game.checkPref("touchscreen", false, val -> control.setInput(!val ? new DesktopInput() : new MobileInput()));
if(Core.settings.getBool("touchscreen")){
control.setInput(new MobileInput());
}
}*/
game.sliderPref("saveinterval", 60, 10, 5 * 120, 10, i -> Core.bundle.format("setting.seconds", i));
if(!mobile){
game.sliderPref("blockselecttimeout", 750, 0, 2000, 50, i -> Core.bundle.format("setting.milliseconds", i));
game.checkPref("crashreport", true);
}
game.checkPref("savecreate", true);
game.checkPref("blockreplace", true);
game.checkPref("conveyorpathfinding", true);
game.checkPref("hints", true);
if(!mobile){
game.checkPref("buildautopause", false);
}
if(steam && !Version.modifier.contains("beta")){
game.checkPref("publichost", false, i -> {
platform.updateLobby();
});
}
game.pref(new Setting(){
@Override
public void add(SettingsTable table){
table.addButton("$tutorial.retake", () -> {
hide();
control.playTutorial();
}).size(220f, 60f).pad(6).left();
table.add();
table.row();
hide();
}
});
graphics.sliderPref("uiscale", 100, 25, 300, 25, s -> {
if(ui.settings != null){
Core.settings.put("uiscalechanged", true);
}
return s + "%";
});
graphics.sliderPref("fpscap", 240, 15, 245, 5, s -> (s > 240 ? Core.bundle.get("setting.fpscap.none") : Core.bundle.format("setting.fpscap.text", s)));
graphics.sliderPref("chatopacity", 100, 0, 100, 5, s -> s + "%");
graphics.sliderPref("lasersopacity", 100, 0, 100, 5, s -> {
if(ui.settings != null){
Core.settings.put("preferredlaseropacity", s);
}
return s + "%";
});
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(Core.graphics.getWidth(), Core.graphics.getHeight());
}
});
graphics.checkPref("borderlesswindow", false, b -> Core.graphics.setUndecorated(b));
Core.graphics.setVSync(Core.settings.getBool("vsync"));
if(Core.settings.getBool("fullscreen")){
Core.app.post(() -> Core.graphics.setFullscreenMode(Core.graphics.getDisplayMode()));
}
if(Core.settings.getBool("borderlesswindow")){
Core.app.post(() -> Core.graphics.setUndecorated(true));
}
}else{
graphics.checkPref("landscape", false, b -> {
if(b){
platform.beginForceLandscape();
}else{
platform.endForceLandscape();
}
});
if(Core.settings.getBool("landscape")){
platform.beginForceLandscape();
}
}
graphics.checkPref("effects", true);
graphics.checkPref("destroyedblocks", true);
graphics.checkPref("playerchat", true);
graphics.checkPref("minimap", !mobile);
graphics.checkPref("position", false);
graphics.checkPref("fps", false);
if(!mobile){
graphics.checkPref("blockselectkeys", true);
}
graphics.checkPref("indicators", true);
graphics.checkPref("animatedwater", !mobile);
if(Shaders.shield != null){
graphics.checkPref("animatedshields", !mobile);
}
graphics.checkPref("bloom", !mobile, val -> renderer.toggleBloom(val));
graphics.checkPref("pixelate", false, val -> {
if(val){
Events.fire(Trigger.enablePixelation);
}
});
graphics.checkPref("linear", !mobile, 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);
}
}
if(!mobile){
Core.settings.put("swapdiagonal", false);
}
}
private void back(){
rebuildMenu();
prefs.clearChildren();
prefs.add(menu);
}
private void visible(int index){
prefs.clearChildren();
prefs.add(new Table[]{game, graphics, sound}[index]);
}
@Override
public void addCloseButton(){
buttons.addImageTextButton("$back", Icon.arrowLeftSmaller, () -> {
if(prefs.getChildren().first() != menu){
back();
}else{
hide();
}
}).size(230f, 64f);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
if(prefs.getChildren().first() != menu){
back();
}else{
hide();
}
}
});
}
}

View File

@@ -0,0 +1,389 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.input.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.*;
import arc.scene.actions.*;
import arc.scene.event.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.content.TechTree.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import mindustry.ui.layout.*;
import mindustry.ui.layout.TreeLayout.*;
import static mindustry.Vars.*;
public class TechTreeDialog extends FloatingDialog{
private final float nodeSize = Scl.scl(60f);
private ObjectSet<TechTreeNode> nodes = new ObjectSet<>();
private TechTreeNode root = new TechTreeNode(TechTree.root, null);
private Rectangle bounds = new Rectangle();
private ItemsDisplay items;
private View view;
public TechTreeDialog(){
super("");
titleTable.remove();
margin(0f).marginBottom(8);
Stack stack = cont.stack(view = new View(), items = new ItemsDisplay()).grow().get();
Events.on(ContentReloadEvent.class, e -> {
nodes.clear();
root = new TechTreeNode(TechTree.root, null);
checkNodes(root);
treeLayout();
stack.getChildren().get(0).remove();
stack.addChildAt(0, view = new View());
});
shown(() -> {
checkNodes(root);
treeLayout();
});
hidden(ui.deploy::setup);
addCloseButton();
buttons.addImageTextButton("$database", Icon.database, () -> {
hide();
ui.database.show();
}).size(210f, 64f);
//scaling/drag input
addListener(new InputListener(){
@Override
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
return true;
}
@Override
public boolean mouseMoved(InputEvent event, float x, float y){
view.requestScroll();
return super.mouseMoved(event, x, y);
}
});
addListener(new ElementGestureListener(){
@Override
public void zoom(InputEvent event, float initialDistance, float distance){
if(view.lastZoom < 0){
view.lastZoom = view.getScaleX();
}
view.setScale(Mathf.clamp(distance / initialDistance * view.lastZoom, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
view.lastZoom = view.getScaleX();
}
@Override
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){
view.panX += deltaX / view.getScaleX();
view.panY += deltaY / view.getScaleY();
view.moved = true;
view.clamp();
}
});
}
void treeLayout(){
RadialTreeLayout layout = new RadialTreeLayout();
LayoutNode node = new LayoutNode(root, null);
layout.layout(node);
float minx = 0f, miny = 0f, maxx = 0f, maxy = 0f;
copyInfo(node);
for(TechTreeNode n : nodes){
if(!n.visible) continue;
minx = Math.min(n.x - n.width/2f, minx);
maxx = Math.max(n.x + n.width/2f, maxx);
miny = Math.min(n.y - n.height/2f, miny);
maxy = Math.max(n.y + n.height/2f, maxy);
}
bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny);
bounds.y += nodeSize*1.5f;
}
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).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, lastZoom = -1;
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(Cicon.medium), Styles.nodei);
button.visible(() -> node.visible);
button.clicked(() -> {
if(moved) return;
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.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 = !locked(node.node) ? Tex.buttonOver : !data.hasItems(node.node.requirements) ? Tex.buttonRed : Tex.button;
((TextureRegionDrawable)button.getStyle().imageUp)
.setRegion(node.visible ? node.node.block.icon(Cicon.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();
}
});
}
setOrigin(Align.center);
setTransform(true);
released(() -> moved = false);
}
void clamp(){
float pad = nodeSize;
float ox = width/2f, oy = height/2f;
float rx = bounds.x + panX + ox, ry = panY + oy + bounds.y;
float rw = bounds.width, rh = bounds.height;
rx = Mathf.clamp(rx, -rw + pad, Core.graphics.getWidth() - pad);
ry = Mathf.clamp(ry, -rh + pad, Core.graphics.getHeight() - pad);
panX = rx - bounds.x - ox;
panY = ry - bounds.y - oy;
}
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();
Sounds.unlock.play();
Events.fire(new ResearchEvent(node.block));
}
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.background(Tex.button).margin(8f);
infoTable.table(b -> {
b.margin(0).left().defaults().left();
b.addImageButton(Icon.infoSmall, Styles.cleari, () -> 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.icon(Cicon.small)).size(8 * 3).padRight(3);
list.add(req.item.localizedName).color(Color.lightGray);
list.label(() -> " " + Math.min(data.getItem(req.item), req.amount) + " / " + req.amount)
.update(l -> l.setColor(data.has(req.item, req.amount) ? Color.lightGray : Color.scarlet));
}).fillX().left();
t.row();
}
});
}else{
desc.add("$completed");
}
}).pad(9);
if(mobile && locked(node)){
b.row();
b.addImageTextButton("$research", Icon.checkSmall, Styles.nodet, () -> unlock(node))
.disabled(i -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3);
}
});
infoTable.row();
if(node.block.description != null){
infoTable.table(t -> t.margin(3f).left().labelWrap(node.block.description).color(Color.lightGray).growX()).fillX();
}
addChild(infoTable);
infoTable.pack();
infoTable.act(Core.graphics.getDeltaTime());
}
@Override
public void drawChildren(){
clamp();
float offsetX = panX + width / 2f, offsetY = panY + height / 2f;
for(TechTreeNode node : nodes){
if(!node.visible) continue;
for(TechTreeNode child : node.children){
if(!child.visible) continue;
Lines.stroke(Scl.scl(4f), locked(node.node) || locked(child.node) ? Pal.gray : Pal.accent);
Draw.alpha(parentAlpha);
Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
}
}
Draw.reset();
super.drawChildren();
}
}
}

View File

@@ -0,0 +1,44 @@
package mindustry.ui.dialogs;
import arc.Core;
import arc.scene.ui.layout.Table;
import mindustry.entities.type.Player;
import mindustry.gen.*;
import mindustry.net.Administration.TraceInfo;
public class TraceDialog extends FloatingDialog{
public TraceDialog(){
super("$trace");
addCloseButton();
setFillParent(false);
}
public void show(Player player, TraceInfo info){
cont.clear();
Table table = new Table(Tex.clear);
table.margin(14);
table.defaults().pad(1);
table.defaults().left();
table.add(Core.bundle.format("trace.playername", player.name));
table.row();
table.add(Core.bundle.format("trace.ip", info.ip));
table.row();
table.add(Core.bundle.format("trace.id", info.uuid));
table.row();
table.add(Core.bundle.format("trace.modclient", info.modded));
table.row();
table.add(Core.bundle.format("trace.mobile", info.mobile));
table.row();
table.add().pad(5);
table.row();
cont.add(table);
show();
}
}

View File

@@ -0,0 +1,168 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import mindustry.game.*;
import mindustry.game.Objectives.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.Cicon;
import static mindustry.Vars.*;
public class ZoneInfoDialog extends FloatingDialog{
private LoadoutDialog loadout = new LoadoutDialog();
public ZoneInfoDialog(){
super("");
titleTable.remove();
addCloseButton();
}
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;
for(ItemStack stack : zone.getLaunchCost()){
if(stack.amount == 0) continue;
if(i++ % 2 == 0){
iteminfo.row();
}
iteminfo.addImage(stack.item.icon(mindustry.ui.Cicon.small)).size(8 * 3).padRight(1);
iteminfo.add(stack.amount + "").color(Color.lightGray).padRight(5);
}
};
rebuildItems.run();
cont.pane(cont -> {
if(zone.locked()){
cont.addImage(Icon.locked);
cont.row();
cont.add("$locked").padBottom(6);
cont.row();
cont.table(req -> {
req.defaults().left();
Array<Objective> zones = zone.requirements.select(o -> !(o instanceof Unlock));
if(!zones.isEmpty()){
req.table(r -> {
r.add("$complete").colspan(2).left();
r.row();
for(Objective o : zones){
r.addImage(Icon.terrain).padRight(4);
r.add(o.display()).color(Color.lightGray);
r.addImage(o.complete() ? Icon.checkSmall : Icon.cancelSmall, o.complete() ? Color.lightGray : Color.scarlet).padLeft(3);
r.row();
}
});
}
req.row();
Array<Unlock> blocks = zone.requirements.select(o -> o instanceof Unlock).as(Unlock.class);
if(!blocks.isEmpty()){
req.table(r -> {
r.add("$research.list").colspan(2).left();
r.row();
for(Unlock blocko : blocks){
r.addImage(blocko.block.icon(mindustry.ui.Cicon.small)).size(8 * 3).padRight(5);
r.add(blocko.block.localizedName).color(Color.lightGray).left();
r.addImage(blocko.block.unlocked() ? Icon.checkSmall : Icon.cancelSmall, blocko.block.unlocked() ? Color.lightGray : Color.scarlet).padLeft(3);
r.row();
}
}).padTop(10);
}
}).growX();
}else{
cont.add(zone.localizedName).color(Pal.accent).growX().center();
cont.row();
cont.addImage().color(Pal.accent).height(3).pad(6).growX();
cont.row();
cont.table(desc -> {
desc.left().defaults().left().width(Core.graphics.isPortrait() ? 350f : 500f);
desc.pane(t -> t.marginRight(12f).add(zone.description).wrap().growX()).fillX().maxHeight(mobile ? 300f : 450f).pad(2).padBottom(8f).get().setScrollingDisabled(true, false);
desc.row();
desc.table(t -> {
t.left();
t.add("$zone.resources").padRight(6);
if(zone.resources.size > 0){
t.table(r -> {
t.left();
int i = 0;
for(Item item : zone.resources){
r.addImage(item.icon(Cicon.small)).size(8 * 3);
if(++i % 4 == 0){
r.row();
}
}
});
}else{
t.add("$none");
}
});
Rules rules = zone.getRules();
desc.row();
desc.add(Core.bundle.format("zone.objective", Core.bundle.get(!rules.attackMode ? "zone.objective.survival" : "zone.objective.attack")));
if(zone.bestWave() > 0){
desc.row();
desc.add(Core.bundle.format("bestwave", zone.bestWave()));
}
});
cont.row();
}
cont.marginRight(12f);
});
cont.row();
cont.addButton(zone.canConfigure() ? "$configure" : Core.bundle.format("configure.locked", zone.configureObjective.display()),
() -> loadout.show(zone.loadout.findCore().itemCapacity, zone.getStartingItems(), zone::resetStartingItems, zone::updateLaunchCost, rebuildItems)
).fillX().pad(3).disabled(b -> !zone.canConfigure());
cont.row();
Button button = cont.addButton(zone.locked() ? "$uncover" : "$launch", () -> {
if(!data.isUnlocked(zone)){
Sounds.unlock.play();
data.unlockContent(zone);
ui.deploy.setup();
setup(zone);
}else{
ui.deploy.hide();
data.removeItems(zone.getLaunchCost());
hide();
control.playZone(zone);
}
}).minWidth(200f).margin(13f).padTop(5).disabled(b -> zone.locked() ? !zone.canUnlock() : !data.hasItems(zone.getLaunchCost())).uniformY().get();
button.row();
button.add(iteminfo);
}
}