Merge branch 'master' of https://github.com/Anuken/Mindustry into map_4
This commit is contained in:
@@ -21,7 +21,7 @@ public class LiquidDisplay extends Table{
|
||||
this.perSecond = perSecond;
|
||||
|
||||
add(new Stack(){{
|
||||
add(new Image(liquid.uiIcon));
|
||||
add(new Image(liquid.uiIcon).setScaling(Scaling.fit));
|
||||
|
||||
if(amount != 0){
|
||||
Table t = new Table().left().bottom();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package mindustry.ui.dialogs;
|
||||
|
||||
import arc.*;
|
||||
import arc.assets.loaders.TextureLoader.*;
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.input.*;
|
||||
@@ -69,6 +71,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
public Table sectorTop = new Table(), notifs = new Table(), expandTable = new Table();
|
||||
public Label hoverLabel = new Label("");
|
||||
|
||||
private Texture[] planetTextures;
|
||||
|
||||
public PlanetDialog(){
|
||||
super("", Styles.fullDialog);
|
||||
|
||||
@@ -87,8 +91,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
//clear all except first, which is the last sector.
|
||||
newPresets.truncate(1);
|
||||
}else if(selected != null){
|
||||
selected = null;
|
||||
updateSelected();
|
||||
selectSector(null);
|
||||
}else{
|
||||
Core.app.post(() -> hide());
|
||||
}
|
||||
@@ -160,6 +163,54 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
});
|
||||
|
||||
shown(this::setup);
|
||||
|
||||
//show selection of Erekir/Serpulo campaign if the user has no bases, and hasn't selected yet (essentially a "have they played campaign before" check)
|
||||
shown(() -> {
|
||||
if(!settings.getBool("campaignselect") && !content.planets().contains(p -> p.sectors.contains(s -> s.hasBase()))){
|
||||
var diag = new BaseDialog("@campaign.select");
|
||||
|
||||
Planet[] selected = {null};
|
||||
var group = new ButtonGroup<>();
|
||||
group.setMinCheckCount(0);
|
||||
state.planet = Planets.sun;
|
||||
Planet[] choices = {Planets.serpulo, Planets.erekir};
|
||||
int i = 0;
|
||||
for(var planet : choices){
|
||||
TextureRegion tex = new TextureRegion(planetTextures[i]);
|
||||
|
||||
diag.cont.button(b -> {
|
||||
b.top();
|
||||
b.add(planet.localizedName).color(Pal.accent).style(Styles.outlineLabel);
|
||||
b.row();
|
||||
b.image(new TextureRegionDrawable(tex)).grow().scaling(Scaling.fit);
|
||||
}, Styles.togglet, () -> selected[0] = planet).size(Core.app.isMobile() ? 220f : 320f).group(group);
|
||||
i ++;
|
||||
}
|
||||
|
||||
diag.cont.row();
|
||||
diag.cont.label(() -> selected[0] == null ? "@campaign.none" : "@campaign." + selected[0].name).labelAlign(Align.center).style(Styles.outlineLabel).width(440f).wrap().colspan(2);
|
||||
|
||||
diag.buttons.button("@ok", Icon.ok, () -> {
|
||||
state.planet = selected[0];
|
||||
lookAt(state.planet.getStartSector());
|
||||
selectSector(state.planet.getStartSector());
|
||||
settings.put("campaignselect", true);
|
||||
diag.hide();
|
||||
}).size(300f, 64f).disabled(b -> selected[0] == null);
|
||||
|
||||
app.post(() -> diag.show());
|
||||
}
|
||||
});
|
||||
|
||||
planetTextures = new Texture[2];
|
||||
String[] names = {"sprites/planets/serpulo.png", "sprites/planets/erekir.png"};
|
||||
for(int i = 0; i < names.length; i++){
|
||||
int fi = i;
|
||||
assets.load(names[i], Texture.class, new TextureParameter(){{
|
||||
minFilter = magFilter = TextureFilter.linear;
|
||||
}}).loaded = t -> planetTextures[fi] = t;
|
||||
assets.finishLoadingAsset(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** show with no limitations, just as a map. */
|
||||
@@ -551,17 +602,14 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
buttons,
|
||||
//planet selection
|
||||
new Table(t -> {
|
||||
t.right();
|
||||
t.top().left();
|
||||
if(content.planets().count(this::selectable) > 1){
|
||||
t.table(Styles.black6, pt -> {
|
||||
pt.add("@planets").color(Pal.accent);
|
||||
pt.row();
|
||||
pt.image().growX().height(4f).pad(6f).color(Pal.accent);
|
||||
pt.row();
|
||||
t.table(Tex.pane, pt -> {
|
||||
pt.margin(4f);
|
||||
for(int i = 0; i < content.planets().size; i++){
|
||||
Planet planet = content.planets().get(i);
|
||||
if(selectable(planet)){
|
||||
pt.button(planet.localizedName, Styles.flatTogglet, () -> {
|
||||
pt.button(planet.localizedName, Icon.icons.get(planet.icon + "Small", Icon.icons.get(planet.icon, Icon.commandRallySmall)), Styles.flatTogglet, () -> {
|
||||
selected = null;
|
||||
launchSector = null;
|
||||
if(state.planet != planet){
|
||||
@@ -570,7 +618,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
rebuildExpand();
|
||||
}
|
||||
settings.put("lastplanet", planet.name);
|
||||
}).width(200).height(40).growX().update(bb -> bb.setChecked(state.planet == planet));
|
||||
}).width(190).height(40).growX().update(bb -> bb.setChecked(state.planet == planet)).with(w -> w.marginLeft(10f)).get().getChildren().get(1).setColor(planet.iconColor);
|
||||
pt.row();
|
||||
}
|
||||
}
|
||||
@@ -943,6 +991,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
}
|
||||
}
|
||||
|
||||
void selectSector(Sector sector){
|
||||
selected = sector;
|
||||
updateSelected();
|
||||
}
|
||||
|
||||
void updateSelected(){
|
||||
Sector sector = selected;
|
||||
Table stable = sectorTop;
|
||||
@@ -1128,8 +1181,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
dialog.buttons.button("@sector.view", Icon.eyeSmall, () -> {
|
||||
dialog.hide();
|
||||
lookAt(attacked);
|
||||
selected = attacked;
|
||||
updateSelected();
|
||||
selectSector(attacked);
|
||||
});
|
||||
dialog.show();
|
||||
|
||||
|
||||
@@ -116,60 +116,7 @@ public class ResearchDialog extends BaseDialog{
|
||||
if(currPlanet != null && currPlanet.techTree != null){
|
||||
switchTree(currPlanet.techTree);
|
||||
}
|
||||
|
||||
items = new ItemSeq(){
|
||||
//store sector item amounts for modifications
|
||||
ObjectMap<Sector, ItemSeq> cache = new ObjectMap<>();
|
||||
|
||||
{
|
||||
//add global counts of each sector
|
||||
for(Planet planet : content.planets()){
|
||||
for(Sector sector : planet.sectors){
|
||||
if(sector.hasBase()){
|
||||
ItemSeq cached = sector.items();
|
||||
cache.put(sector, cached);
|
||||
cached.each((item, amount) -> {
|
||||
values[item.id] += Math.max(amount, 0);
|
||||
total += Math.max(amount, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//this is the only method that actually modifies the sequence itself.
|
||||
@Override
|
||||
public void add(Item item, int amount){
|
||||
//only have custom removal logic for when the sequence gets items taken out of it (e.g. research)
|
||||
if(amount < 0){
|
||||
//remove items from each sector's storage, one by one
|
||||
|
||||
//negate amount since it's being *removed* - this makes it positive
|
||||
amount = -amount;
|
||||
|
||||
//% that gets removed from each sector
|
||||
double percentage = (double)amount / get(item);
|
||||
int[] counter = {amount};
|
||||
cache.each((sector, seq) -> {
|
||||
if(counter[0] == 0) return;
|
||||
|
||||
//amount that will be removed
|
||||
int toRemove = Math.min((int)Math.ceil(percentage * seq.get(item)), counter[0]);
|
||||
|
||||
//actually remove it from the sector
|
||||
sector.removeItem(item, toRemove);
|
||||
seq.remove(item, toRemove);
|
||||
|
||||
counter[0] -= toRemove;
|
||||
});
|
||||
|
||||
//negate again to display correct number
|
||||
amount = -amount;
|
||||
}
|
||||
|
||||
super.add(item, amount);
|
||||
}
|
||||
};
|
||||
rebuildItems();
|
||||
|
||||
checkNodes(root);
|
||||
treeLayout();
|
||||
@@ -240,6 +187,68 @@ public class ResearchDialog extends BaseDialog{
|
||||
});
|
||||
}
|
||||
|
||||
public void rebuildItems(){
|
||||
items = new ItemSeq(){
|
||||
//store sector item amounts for modifications
|
||||
ObjectMap<Sector, ItemSeq> cache = new ObjectMap<>();
|
||||
|
||||
{
|
||||
//first, find a planet associated with the current tech tree
|
||||
Planet rootPlanet = lastNode.planet != null ? lastNode.planet : content.planets().find(p -> p.techTree == lastNode);
|
||||
|
||||
//if there is no root, fall back to serpulo
|
||||
if(rootPlanet == null) rootPlanet = Planets.serpulo;
|
||||
|
||||
//add global counts of each sector
|
||||
for(Sector sector : rootPlanet.sectors){
|
||||
if(sector.hasBase()){
|
||||
ItemSeq cached = sector.items();
|
||||
cache.put(sector, cached);
|
||||
cached.each((item, amount) -> {
|
||||
values[item.id] += Math.max(amount, 0);
|
||||
total += Math.max(amount, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//this is the only method that actually modifies the sequence itself.
|
||||
@Override
|
||||
public void add(Item item, int amount){
|
||||
//only have custom removal logic for when the sequence gets items taken out of it (e.g. research)
|
||||
if(amount < 0){
|
||||
//remove items from each sector's storage, one by one
|
||||
|
||||
//negate amount since it's being *removed* - this makes it positive
|
||||
amount = -amount;
|
||||
|
||||
//% that gets removed from each sector
|
||||
double percentage = (double)amount / get(item);
|
||||
int[] counter = {amount};
|
||||
cache.each((sector, seq) -> {
|
||||
if(counter[0] == 0) return;
|
||||
|
||||
//amount that will be removed
|
||||
int toRemove = Math.min((int)Math.ceil(percentage * seq.get(item)), counter[0]);
|
||||
|
||||
//actually remove it from the sector
|
||||
sector.removeItem(item, toRemove);
|
||||
seq.remove(item, toRemove);
|
||||
|
||||
counter[0] -= toRemove;
|
||||
});
|
||||
|
||||
//negate again to display correct number
|
||||
amount = -amount;
|
||||
}
|
||||
|
||||
super.add(item, amount);
|
||||
}
|
||||
};
|
||||
|
||||
itemDisplay.rebuild(items);
|
||||
}
|
||||
|
||||
public @Nullable TechNode getPrefRoot(){
|
||||
Planet currPlanet = ui.planet.isShown() ?
|
||||
ui.planet.state.planet :
|
||||
@@ -253,6 +262,8 @@ public class ResearchDialog extends BaseDialog{
|
||||
root = new TechTreeNode(node, null);
|
||||
lastNode = node;
|
||||
view.rebuildAll();
|
||||
|
||||
rebuildItems();
|
||||
}
|
||||
|
||||
public void rebuildTree(TechNode node){
|
||||
|
||||
@@ -12,6 +12,7 @@ import arc.scene.ui.*;
|
||||
import arc.scene.ui.ImageButton.*;
|
||||
import arc.scene.ui.TextButton.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -26,6 +27,7 @@ public class MenuFragment{
|
||||
private Table container, submenu;
|
||||
private Button currentMenu;
|
||||
private MenuRenderer renderer;
|
||||
private Seq<MenuButton> customButtons = new Seq<>();
|
||||
|
||||
public void build(Group parent){
|
||||
renderer = new MenuRenderer();
|
||||
@@ -40,16 +42,21 @@ public class MenuFragment{
|
||||
parent.fill((x, y, w, h) -> renderer.render());
|
||||
|
||||
parent.fill(c -> {
|
||||
container = c;
|
||||
c.name = "menu container";
|
||||
c.pane(Styles.noBarPane, cont -> {
|
||||
container = cont;
|
||||
cont.name = "menu container";
|
||||
|
||||
if(!mobile){
|
||||
buildDesktop();
|
||||
Events.on(ResizeEvent.class, event -> buildDesktop());
|
||||
}else{
|
||||
buildMobile();
|
||||
Events.on(ResizeEvent.class, event -> buildMobile());
|
||||
}
|
||||
if(!mobile){
|
||||
c.left();
|
||||
buildDesktop();
|
||||
Events.on(ResizeEvent.class, event -> buildDesktop());
|
||||
}else{
|
||||
buildMobile();
|
||||
Events.on(ResizeEvent.class, event -> buildMobile());
|
||||
}
|
||||
}).with(pane -> {
|
||||
pane.setOverscroll(false, false);
|
||||
}).grow();
|
||||
});
|
||||
|
||||
parent.fill(c -> c.bottom().right().button(Icon.discord, new ImageButtonStyle(){{
|
||||
@@ -63,8 +70,6 @@ public class MenuFragment{
|
||||
fontColor = Color.white;
|
||||
up = infoBanner;
|
||||
}}, ui.about::show).size(84, 45).name("info"));
|
||||
|
||||
|
||||
}else if(becontrol.active()){
|
||||
parent.fill(c -> c.bottom().right().button("@be.check", Icon.refresh, () -> {
|
||||
ui.loadfrag.show();
|
||||
@@ -83,7 +88,7 @@ public class MenuFragment{
|
||||
parent.fill((x, y, w, h) -> {
|
||||
TextureRegion logo = Core.atlas.find("logo");
|
||||
float width = Core.graphics.getWidth(), height = Core.graphics.getHeight() - Core.scene.marginTop;
|
||||
float logoscl = Scl.scl(1);
|
||||
float logoscl = Scl.scl(1) * logo.scale;
|
||||
float logow = Math.min(logo.width * logoscl, Core.graphics.getWidth() - Scl.scl(20));
|
||||
float logoh = logow * (float)logo.height / logo.width;
|
||||
|
||||
@@ -116,23 +121,28 @@ public class MenuFragment{
|
||||
mods = new MobileButton(Icon.book, "@mods", ui.mods::show),
|
||||
exit = new MobileButton(Icon.exit, "@quit", () -> Core.app.exit());
|
||||
|
||||
Seq<MobileButton> customs = customButtons.map(b -> new MobileButton(b.icon, b.text, b.runnable == null ? () -> {} : b.runnable));
|
||||
|
||||
if(!Core.graphics.isPortrait()){
|
||||
container.marginTop(60f);
|
||||
container.add(play);
|
||||
container.add(join);
|
||||
container.add(custom);
|
||||
container.add(maps);
|
||||
// add odd custom buttons
|
||||
for(int i = 1; i < customs.size; i += 2){
|
||||
container.add(customs.get(i));
|
||||
}
|
||||
container.row();
|
||||
|
||||
container.table(table -> {
|
||||
table.defaults().set(container.defaults());
|
||||
|
||||
table.add(editor);
|
||||
table.add(tools);
|
||||
|
||||
table.add(mods);
|
||||
if(!ios) table.add(exit);
|
||||
}).colspan(4);
|
||||
container.add(editor);
|
||||
container.add(tools);
|
||||
container.add(mods);
|
||||
// add even custom buttons (before the exit button)
|
||||
for(int i = 0; i < customs.size; i += 2){
|
||||
container.add(customs.get(i));
|
||||
}
|
||||
if(!ios) container.add(exit);
|
||||
}else{
|
||||
container.marginTop(0f);
|
||||
container.add(play);
|
||||
@@ -144,13 +154,13 @@ public class MenuFragment{
|
||||
container.add(editor);
|
||||
container.add(tools);
|
||||
container.row();
|
||||
|
||||
container.table(table -> {
|
||||
table.defaults().set(container.defaults());
|
||||
|
||||
table.add(mods);
|
||||
if(!ios) table.add(exit);
|
||||
}).colspan(2);
|
||||
container.add(mods);
|
||||
// add custom buttons
|
||||
for(int i = 0; i < customs.size; i++){
|
||||
container.add(customs.get(i));
|
||||
if(i % 2 == 0) container.row();
|
||||
}
|
||||
if(!ios) container.add(exit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,23 +178,23 @@ public class MenuFragment{
|
||||
t.name = "buttons";
|
||||
|
||||
buttons(t,
|
||||
new Buttoni("@play", Icon.play,
|
||||
new Buttoni("@campaign", Icon.play, () -> checkPlay(ui.planet::show)),
|
||||
new Buttoni("@joingame", Icon.add, () -> checkPlay(ui.join::show)),
|
||||
new Buttoni("@customgame", Icon.terrain, () -> checkPlay(ui.custom::show)),
|
||||
new Buttoni("@loadgame", Icon.download, () -> checkPlay(ui.load::show))
|
||||
new MenuButton("@play", Icon.play,
|
||||
new MenuButton("@campaign", Icon.play, () -> checkPlay(ui.planet::show)),
|
||||
new MenuButton("@joingame", Icon.add, () -> checkPlay(ui.join::show)),
|
||||
new MenuButton("@customgame", Icon.terrain, () -> checkPlay(ui.custom::show)),
|
||||
new MenuButton("@loadgame", Icon.download, () -> checkPlay(ui.load::show))
|
||||
),
|
||||
new Buttoni("@database.button", Icon.menu,
|
||||
new Buttoni("@schematics", Icon.paste, ui.schematics::show),
|
||||
new Buttoni("@database", Icon.book, ui.database::show),
|
||||
new Buttoni("@about.button", Icon.info, ui.about::show)
|
||||
new MenuButton("@database.button", Icon.menu,
|
||||
new MenuButton("@schematics", Icon.paste, ui.schematics::show),
|
||||
new MenuButton("@database", Icon.book, ui.database::show),
|
||||
new MenuButton("@about.button", Icon.info, ui.about::show)
|
||||
),
|
||||
new Buttoni("@editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("@workshop", Icon.steam, platform::openWorkshop) : null,
|
||||
new Buttoni("@mods", Icon.book, ui.mods::show),
|
||||
new Buttoni("@settings", Icon.settings, ui.settings::show),
|
||||
new Buttoni("@quit", Icon.exit, Core.app::exit)
|
||||
new MenuButton("@editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new MenuButton("@workshop", Icon.steam, platform::openWorkshop) : null,
|
||||
new MenuButton("@mods", Icon.book, ui.mods::show),
|
||||
new MenuButton("@settings", Icon.settings, ui.settings::show)
|
||||
);
|
||||
|
||||
buttons(t, customButtons.toArray(MenuButton.class));
|
||||
buttons(t, new MenuButton("@quit", Icon.exit, Core.app::exit));
|
||||
}).width(width).growY();
|
||||
|
||||
container.table(background, t -> {
|
||||
@@ -199,7 +209,6 @@ public class MenuFragment{
|
||||
}
|
||||
|
||||
private void checkPlay(Runnable run){
|
||||
|
||||
if(!mods.hasContentErrors()){
|
||||
run.run();
|
||||
}else{
|
||||
@@ -222,8 +231,8 @@ public class MenuFragment{
|
||||
submenu.actions(Actions.alpha(1f), Actions.alpha(0f, 0.2f, Interp.fade), Actions.run(() -> submenu.clearChildren()));
|
||||
}
|
||||
|
||||
private void buttons(Table t, Buttoni... buttons){
|
||||
for(Buttoni b : buttons){
|
||||
private void buttons(Table t, MenuButton... buttons){
|
||||
for(MenuButton b : buttons){
|
||||
if(b == null) continue;
|
||||
Button[] out = {null};
|
||||
out[0] = t.button(b.text, b.icon, Styles.flatToggleMenut, () -> {
|
||||
@@ -251,24 +260,56 @@ public class MenuFragment{
|
||||
}
|
||||
}
|
||||
|
||||
private static class Buttoni{
|
||||
final Drawable icon;
|
||||
final String text;
|
||||
final Runnable runnable;
|
||||
final Buttoni[] submenu;
|
||||
/** Adds a custom button to the menu. */
|
||||
public void addButton(String text, Drawable icon, Runnable callback){
|
||||
addButton(new MenuButton(text, icon, callback));
|
||||
}
|
||||
|
||||
public Buttoni(String text, Drawable icon, Runnable runnable){
|
||||
/** Adds a custom button to the menu. */
|
||||
public void addButton(String text, Runnable callback){
|
||||
addButton(text, Styles.none, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom button to the menu.
|
||||
* If {@link MenuButton#submenu} is null or the player is on mobile, {@link MenuButton#runnable} is invoked on click.
|
||||
* Otherwise, {@link MenuButton#submenu} is shown.
|
||||
*/
|
||||
public void addButton(MenuButton button){
|
||||
customButtons.add(button);
|
||||
}
|
||||
|
||||
/** Represents a menu button definition. */
|
||||
public static class MenuButton{
|
||||
public final Drawable icon;
|
||||
public final String text;
|
||||
/** Runnable ran when the button is clicked. Ignored on desktop if {@link #submenu} is not null. */
|
||||
public final Runnable runnable;
|
||||
/** Submenu shown when this button is clicked. Used instead of {@link #runnable} on desktop. */
|
||||
public final @Nullable MenuButton[] submenu;
|
||||
|
||||
/** Constructs a simple menu button, which behaves the same way on desktop and mobile. */
|
||||
public MenuButton(String text, Drawable icon, Runnable runnable){
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
this.runnable = runnable;
|
||||
this.submenu = null;
|
||||
}
|
||||
|
||||
public Buttoni(String text, Drawable icon, Buttoni... buttons){
|
||||
/** Constructs a button that runs the runnable when clicked on mobile or shows the submenu on desktop. */
|
||||
public MenuButton(String text, Drawable icon, Runnable runnable, MenuButton... submenu){
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
this.runnable = runnable;
|
||||
this.submenu = submenu;
|
||||
}
|
||||
|
||||
/** Comstructs a desktop-only button; used internally. */
|
||||
MenuButton(String text, Drawable icon, MenuButton... submenu){
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
this.runnable = () -> {};
|
||||
this.submenu = buttons;
|
||||
this.submenu = submenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user