it is done
This commit is contained in:
118
core/src/mindustry/ui/dialogs/AboutDialog.java
Normal file
118
core/src/mindustry/ui/dialogs/AboutDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
59
core/src/mindustry/ui/dialogs/AdminsDialog.java
Normal file
59
core/src/mindustry/ui/dialogs/AdminsDialog.java
Normal 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);
|
||||
}
|
||||
}
|
||||
55
core/src/mindustry/ui/dialogs/BansDialog.java
Normal file
55
core/src/mindustry/ui/dialogs/BansDialog.java
Normal 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);
|
||||
}
|
||||
}
|
||||
63
core/src/mindustry/ui/dialogs/ColorPicker.java
Normal file
63
core/src/mindustry/ui/dialogs/ColorPicker.java
Normal 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
28
core/src/mindustry/ui/dialogs/ContentInfoDialog.java
Normal file
28
core/src/mindustry/ui/dialogs/ContentInfoDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
27
core/src/mindustry/ui/dialogs/ControlsDialog.java
Normal file
27
core/src/mindustry/ui/dialogs/ControlsDialog.java
Normal 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
92
core/src/mindustry/ui/dialogs/CustomGameDialog.java
Normal file
92
core/src/mindustry/ui/dialogs/CustomGameDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
220
core/src/mindustry/ui/dialogs/CustomRulesDialog.java
Normal file
220
core/src/mindustry/ui/dialogs/CustomRulesDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
86
core/src/mindustry/ui/dialogs/DatabaseDialog.java
Normal file
86
core/src/mindustry/ui/dialogs/DatabaseDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
319
core/src/mindustry/ui/dialogs/DeployDialog.java
Normal file
319
core/src/mindustry/ui/dialogs/DeployDialog.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
core/src/mindustry/ui/dialogs/DiscordDialog.java
Normal file
52
core/src/mindustry/ui/dialogs/DiscordDialog.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
309
core/src/mindustry/ui/dialogs/FileChooser.java
Normal file
309
core/src/mindustry/ui/dialogs/FileChooser.java
Normal 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() + "--");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
67
core/src/mindustry/ui/dialogs/FloatingDialog.java
Normal file
67
core/src/mindustry/ui/dialogs/FloatingDialog.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
102
core/src/mindustry/ui/dialogs/GameOverDialog.java
Normal file
102
core/src/mindustry/ui/dialogs/GameOverDialog.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
core/src/mindustry/ui/dialogs/HostDialog.java
Normal file
96
core/src/mindustry/ui/dialogs/HostDialog.java
Normal 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
417
core/src/mindustry/ui/dialogs/JoinDialog.java
Normal file
417
core/src/mindustry/ui/dialogs/JoinDialog.java
Normal 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(){
|
||||
}
|
||||
}
|
||||
}
|
||||
90
core/src/mindustry/ui/dialogs/LanguageDialog.java
Normal file
90
core/src/mindustry/ui/dialogs/LanguageDialog.java
Normal 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());
|
||||
}
|
||||
}
|
||||
216
core/src/mindustry/ui/dialogs/LoadDialog.java
Normal file
216
core/src/mindustry/ui/dialogs/LoadDialog.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
127
core/src/mindustry/ui/dialogs/LoadoutDialog.java
Normal file
127
core/src/mindustry/ui/dialogs/LoadoutDialog.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
core/src/mindustry/ui/dialogs/MapPlayDialog.java
Normal file
110
core/src/mindustry/ui/dialogs/MapPlayDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
220
core/src/mindustry/ui/dialogs/MapsDialog.java
Normal file
220
core/src/mindustry/ui/dialogs/MapsDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
70
core/src/mindustry/ui/dialogs/MinimapDialog.java
Normal file
70
core/src/mindustry/ui/dialogs/MinimapDialog.java
Normal 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));
|
||||
}
|
||||
}
|
||||
195
core/src/mindustry/ui/dialogs/ModsDialog.java
Normal file
195
core/src/mindustry/ui/dialogs/ModsDialog.java
Normal 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);
|
||||
}
|
||||
}
|
||||
51
core/src/mindustry/ui/dialogs/PaletteDialog.java
Normal file
51
core/src/mindustry/ui/dialogs/PaletteDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
134
core/src/mindustry/ui/dialogs/PausedDialog.java
Normal file
134
core/src/mindustry/ui/dialogs/PausedDialog.java
Normal 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
62
core/src/mindustry/ui/dialogs/SaveDialog.java
Normal file
62
core/src/mindustry/ui/dialogs/SaveDialog.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
325
core/src/mindustry/ui/dialogs/SchematicsDialog.java
Normal file
325
core/src/mindustry/ui/dialogs/SchematicsDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
376
core/src/mindustry/ui/dialogs/SettingsMenuDialog.java
Normal file
376
core/src/mindustry/ui/dialogs/SettingsMenuDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
389
core/src/mindustry/ui/dialogs/TechTreeDialog.java
Normal file
389
core/src/mindustry/ui/dialogs/TechTreeDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
44
core/src/mindustry/ui/dialogs/TraceDialog.java
Normal file
44
core/src/mindustry/ui/dialogs/TraceDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
168
core/src/mindustry/ui/dialogs/ZoneInfoDialog.java
Normal file
168
core/src/mindustry/ui/dialogs/ZoneInfoDialog.java
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user