it is done
This commit is contained in:
83
core/src/mindustry/ui/fragments/BlockConfigFragment.java
Normal file
83
core/src/mindustry/ui/fragments/BlockConfigFragment.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.*;
|
||||
import arc.scene.actions.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BlockConfigFragment extends Fragment{
|
||||
private Table table = new Table();
|
||||
private Tile configTile;
|
||||
private Block configBlock;
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
table.visible(false);
|
||||
parent.addChild(table);
|
||||
|
||||
//hacky way to hide block config when in menu
|
||||
//TODO remove?
|
||||
Core.scene.add(new Element(){
|
||||
@Override
|
||||
public void act(float delta){
|
||||
super.act(delta);
|
||||
if(state.is(State.menu)){
|
||||
table.visible(false);
|
||||
configTile = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isShown(){
|
||||
return table.isVisible() && configTile != null;
|
||||
}
|
||||
|
||||
public Tile getSelectedTile(){
|
||||
return configTile;
|
||||
}
|
||||
|
||||
public void showConfig(Tile tile){
|
||||
configTile = tile;
|
||||
configBlock = tile.block();
|
||||
|
||||
table.visible(true);
|
||||
table.clear();
|
||||
tile.block().buildConfiguration(tile, table);
|
||||
table.pack();
|
||||
table.setTransform(true);
|
||||
table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true),
|
||||
Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out));
|
||||
|
||||
table.update(() -> {
|
||||
if(configTile != null && configTile.block().shouldHideConfigure(configTile, player)){
|
||||
hideConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
table.setOrigin(Align.center);
|
||||
if(configTile == null || configTile.block() == Blocks.air || configTile.block() != configBlock){
|
||||
hideConfig();
|
||||
}else{
|
||||
configTile.block().updateTableAlign(tile, table);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasConfigMouse(){
|
||||
Element e = Core.scene.hit(Core.input.mouseX(), Core.graphics.getHeight() - Core.input.mouseY(), true);
|
||||
return e != null && (e == table || e.isDescendantOf(table));
|
||||
}
|
||||
|
||||
public void hideConfig(){
|
||||
configTile = null;
|
||||
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.visible(false));
|
||||
}
|
||||
}
|
||||
217
core/src/mindustry/ui/fragments/BlockInventoryFragment.java
Normal file
217
core/src/mindustry/ui/fragments/BlockInventoryFragment.java
Normal file
@@ -0,0 +1,217 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import arc.struct.*;
|
||||
import arc.func.*;
|
||||
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.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.Cicon;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BlockInventoryFragment extends Fragment{
|
||||
private final static float holdWithdraw = 20f;
|
||||
|
||||
private Table table = new Table();
|
||||
private Tile tile;
|
||||
private float holdTime = 0f;
|
||||
private boolean holding;
|
||||
private Item lastItem;
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
||||
public static void requestItem(Player player, Tile tile, Item item, int amount){
|
||||
if(player == null || tile == null || !player.timer.get(Player.timerTransfer, 20) || !tile.interactable(player.getTeam())) return;
|
||||
if(!Units.canInteract(player, tile)) return;
|
||||
|
||||
int removed = tile.block().removeStack(tile, item, amount);
|
||||
|
||||
player.addItem(item, removed);
|
||||
Events.fire(new WithdrawEvent(tile, player, item, amount));
|
||||
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
||||
Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
table.setName("inventory");
|
||||
table.setTransform(true);
|
||||
parent.setTransform(true);
|
||||
parent.addChild(table);
|
||||
}
|
||||
|
||||
public void showFor(Tile t){
|
||||
if(this.tile == t){
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
this.tile = t;
|
||||
if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0)
|
||||
return;
|
||||
rebuild(true);
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
if(table == null) return;
|
||||
|
||||
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.run(() -> {
|
||||
table.clearChildren();
|
||||
table.clearListeners();
|
||||
table.update(null);
|
||||
}), Actions.visible(false));
|
||||
table.touchable(Touchable.disabled);
|
||||
tile = null;
|
||||
}
|
||||
|
||||
private void rebuild(boolean actions){
|
||||
|
||||
IntSet container = new IntSet();
|
||||
|
||||
table.clearChildren();
|
||||
table.clearActions();
|
||||
table.background(Tex.inventory);
|
||||
table.touchable(Touchable.enabled);
|
||||
table.update(() -> {
|
||||
|
||||
if(state.is(State.menu) || tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0){
|
||||
hide();
|
||||
}else{
|
||||
if(holding && lastItem != null){
|
||||
holdTime += Time.delta();
|
||||
|
||||
if(holdTime >= holdWithdraw){
|
||||
int amount = Math.min(tile.entity.items.get(lastItem), player.maxAccepted(lastItem));
|
||||
Call.requestItem(player, tile, lastItem, amount);
|
||||
holding = false;
|
||||
holdTime = 0f;
|
||||
|
||||
if(net.client()) Events.fire(new WithdrawEvent(tile, player, lastItem, amount));
|
||||
}
|
||||
}
|
||||
|
||||
updateTablePosition();
|
||||
if(tile.block().hasItems){
|
||||
for(int i = 0; i < content.items().size; i++){
|
||||
boolean has = tile.entity.items.has(content.item(i));
|
||||
if(has != container.contains(i)){
|
||||
rebuild(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
int cols = 3;
|
||||
int row = 0;
|
||||
|
||||
table.margin(4f);
|
||||
table.defaults().size(8 * 5).pad(4f);
|
||||
|
||||
if(tile.block().hasItems){
|
||||
|
||||
for(int i = 0; i < content.items().size; i++){
|
||||
Item item = content.item(i);
|
||||
if(!tile.entity.items.has(item)) continue;
|
||||
|
||||
container.add(i);
|
||||
|
||||
Boolp canPick = () -> player.acceptsItem(item) && !state.isPaused();
|
||||
|
||||
HandCursorListener l = new HandCursorListener();
|
||||
l.setEnabled(canPick);
|
||||
|
||||
Element image = itemImage(item.icon(Cicon.xlarge), () -> {
|
||||
if(tile == null || tile.entity == null){
|
||||
return "";
|
||||
}
|
||||
return round(tile.entity.items.get(item));
|
||||
});
|
||||
image.addListener(l);
|
||||
|
||||
image.addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
if(!canPick.get() || tile == null || tile.entity == null || tile.entity.items == null || !tile.entity.items.has(item)) return false;
|
||||
int amount = Math.min(1, player.maxAccepted(item));
|
||||
if(amount > 0){
|
||||
Call.requestItem(player, tile, item, amount);
|
||||
lastItem = item;
|
||||
holding = true;
|
||||
holdTime = 0f;
|
||||
if(net.client()) Events.fire(new WithdrawEvent(tile, player, item, amount));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
holding = false;
|
||||
lastItem = null;
|
||||
}
|
||||
});
|
||||
table.add(image);
|
||||
|
||||
if(row++ % cols == cols - 1) table.row();
|
||||
}
|
||||
}
|
||||
|
||||
if(row == 0){
|
||||
table.setSize(0f, 0f);
|
||||
}
|
||||
|
||||
updateTablePosition();
|
||||
|
||||
table.visible(true);
|
||||
|
||||
if(actions){
|
||||
table.setScale(0f, 1f);
|
||||
table.actions(Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out));
|
||||
}else{
|
||||
table.setScale(1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
private String round(float f){
|
||||
f = (int)f;
|
||||
if(f >= 1000000){
|
||||
return (int)(f / 1000000f) + "[gray]" + Core.bundle.getOrNull("unit.millions") + "[]";
|
||||
}else if(f >= 1000){
|
||||
return (int)(f / 1000) + Core.bundle.getOrNull("unit.thousands");
|
||||
}else{
|
||||
return (int)f + "";
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTablePosition(){
|
||||
Vector2 v = Core.input.mouseScreen(tile.drawx() + tile.block().size * tilesize / 2f, tile.drawy() + tile.block().size * tilesize / 2f);
|
||||
table.pack();
|
||||
table.setPosition(v.x, v.y, Align.topLeft);
|
||||
}
|
||||
|
||||
private Element itemImage(TextureRegion region, Prov<CharSequence> text){
|
||||
Stack stack = new Stack();
|
||||
|
||||
Table t = new Table().left().bottom();
|
||||
t.label(text);
|
||||
|
||||
stack.add(new Image(region));
|
||||
stack.add(t);
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
252
core/src/mindustry/ui/fragments/ChatFragment.java
Normal file
252
core/src/mindustry/ui/fragments/ChatFragment.java
Normal file
@@ -0,0 +1,252 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.Input.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.Label.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static arc.Core.*;
|
||||
import static mindustry.Vars.net;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class ChatFragment extends Table{
|
||||
private final static int messagesShown = 10;
|
||||
private Array<ChatMessage> messages = new Array<>();
|
||||
private float fadetime;
|
||||
private boolean shown = false;
|
||||
private TextField chatfield;
|
||||
private Label fieldlabel = new Label(">");
|
||||
private BitmapFont font;
|
||||
private GlyphLayout layout = new GlyphLayout();
|
||||
private float offsetx = Scl.scl(4), offsety = Scl.scl(4), fontoffsetx = Scl.scl(2), chatspace = Scl.scl(50);
|
||||
private Color shadowColor = new Color(0, 0, 0, 0.4f);
|
||||
private float textspacing = Scl.scl(10);
|
||||
private Array<String> history = new Array<>();
|
||||
private int historyPos = 0;
|
||||
private int scrollPos = 0;
|
||||
private Fragment container = new Fragment(){
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
scene.add(ChatFragment.this);
|
||||
}
|
||||
};
|
||||
|
||||
public ChatFragment(){
|
||||
super();
|
||||
|
||||
setFillParent(true);
|
||||
font = Fonts.def;
|
||||
|
||||
visible(() -> {
|
||||
if(!net.active() && messages.size > 0){
|
||||
clearMessages();
|
||||
|
||||
if(shown){
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
return net.active();
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
|
||||
if(net.active() && input.keyTap(Binding.chat) && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){
|
||||
toggle();
|
||||
}
|
||||
|
||||
if(shown){
|
||||
if(input.keyTap(Binding.chat_history_prev) && historyPos < history.size - 1){
|
||||
if(historyPos == 0) history.set(0, chatfield.getText());
|
||||
historyPos++;
|
||||
updateChat();
|
||||
}
|
||||
if(input.keyTap(Binding.chat_history_next) && historyPos > 0){
|
||||
historyPos--;
|
||||
updateChat();
|
||||
}
|
||||
scrollPos = (int)Mathf.clamp(scrollPos + input.axis(Binding.chat_scroll), 0, Math.max(0, messages.size - messagesShown));
|
||||
}
|
||||
});
|
||||
|
||||
history.insert(0, "");
|
||||
setup();
|
||||
}
|
||||
|
||||
public Fragment container(){
|
||||
return container;
|
||||
}
|
||||
|
||||
public void clearMessages(){
|
||||
messages.clear();
|
||||
history.clear();
|
||||
history.insert(0, "");
|
||||
}
|
||||
|
||||
private void setup(){
|
||||
fieldlabel.setStyle(new LabelStyle(fieldlabel.getStyle()));
|
||||
fieldlabel.getStyle().font = font;
|
||||
fieldlabel.setStyle(fieldlabel.getStyle());
|
||||
|
||||
chatfield = new TextField("", new TextField.TextFieldStyle(scene.getStyle(TextField.TextFieldStyle.class)));
|
||||
chatfield.setMaxLength(Vars.maxTextLength);
|
||||
chatfield.getStyle().background = null;
|
||||
chatfield.getStyle().font = Fonts.chat;
|
||||
chatfield.getStyle().fontColor = Color.white;
|
||||
chatfield.setStyle(chatfield.getStyle());
|
||||
|
||||
bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(6f);
|
||||
|
||||
add(chatfield).padBottom(offsety).padLeft(offsetx).growX().padRight(offsetx).height(28);
|
||||
|
||||
if(Vars.mobile){
|
||||
marginBottom(105f);
|
||||
marginRight(240f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float opacity = Core.settings.getInt("chatopacity") / 100f;
|
||||
float textWidth = Math.min(Core.graphics.getWidth()/1.5f, Scl.scl(700f));
|
||||
|
||||
Draw.color(shadowColor);
|
||||
|
||||
if(shown){
|
||||
Fill.crect(offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight() - 1);
|
||||
}
|
||||
|
||||
super.draw();
|
||||
|
||||
float spacing = chatspace;
|
||||
|
||||
chatfield.visible(shown);
|
||||
fieldlabel.visible(shown);
|
||||
|
||||
Draw.color(shadowColor);
|
||||
Draw.alpha(shadowColor.a * opacity);
|
||||
|
||||
float theight = offsety + spacing + getMarginBottom();
|
||||
for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || shown); i++){
|
||||
|
||||
layout.setText(font, messages.get(i).formattedMessage, Color.white, textWidth, Align.bottomLeft, true);
|
||||
theight += layout.height + textspacing;
|
||||
if(i - scrollPos == 0) theight -= textspacing + 1;
|
||||
|
||||
font.getCache().clear();
|
||||
font.getCache().addText(messages.get(i).formattedMessage, fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true);
|
||||
|
||||
if(!shown && fadetime - i < 1f && fadetime - i >= 0f){
|
||||
font.getCache().setAlphas((fadetime - i) * opacity);
|
||||
Draw.color(0, 0, 0, shadowColor.a * (fadetime - i) * opacity);
|
||||
}else{
|
||||
font.getCache().setAlphas(opacity);
|
||||
}
|
||||
|
||||
Fill.crect(offsetx, theight - layout.height - 2, textWidth + Scl.scl(4f), layout.height + textspacing);
|
||||
Draw.color(shadowColor);
|
||||
Draw.alpha(opacity * shadowColor.a);
|
||||
|
||||
font.getCache().draw();
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
if(fadetime > 0 && !shown)
|
||||
fadetime -= Time.delta() / 180f;
|
||||
}
|
||||
|
||||
private void sendMessage(){
|
||||
String message = chatfield.getText();
|
||||
clearChatInput();
|
||||
|
||||
if(message.replaceAll(" ", "").isEmpty()) return;
|
||||
|
||||
history.insert(1, message);
|
||||
|
||||
Call.sendChatMessage(message);
|
||||
}
|
||||
|
||||
public void toggle(){
|
||||
|
||||
if(!shown){
|
||||
scene.setKeyboardFocus(chatfield);
|
||||
shown = !shown;
|
||||
if(mobile){
|
||||
TextInput input = new TextInput();
|
||||
input.maxLength = maxTextLength;
|
||||
input.accepted = text -> {
|
||||
chatfield.setText(text);
|
||||
sendMessage();
|
||||
hide();
|
||||
Core.input.setOnscreenKeyboardVisible(false);
|
||||
};
|
||||
input.canceled = this::hide;
|
||||
Core.input.getTextInput(input);
|
||||
}else{
|
||||
chatfield.fireClick();
|
||||
}
|
||||
}else{
|
||||
scene.setKeyboardFocus(null);
|
||||
shown = !shown;
|
||||
scrollPos = 0;
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
scene.setKeyboardFocus(null);
|
||||
shown = false;
|
||||
clearChatInput();
|
||||
}
|
||||
|
||||
public void updateChat(){
|
||||
chatfield.setText(history.get(historyPos));
|
||||
chatfield.setCursorPosition(chatfield.getText().length());
|
||||
}
|
||||
|
||||
public void clearChatInput(){
|
||||
historyPos = 0;
|
||||
history.set(0, "");
|
||||
chatfield.setText("");
|
||||
}
|
||||
|
||||
public boolean shown(){
|
||||
return shown;
|
||||
}
|
||||
|
||||
public void addMessage(String message, String sender){
|
||||
messages.insert(0, new ChatMessage(message, sender));
|
||||
|
||||
fadetime += 1f;
|
||||
fadetime = Math.min(fadetime, messagesShown) + 1f;
|
||||
}
|
||||
|
||||
private static class ChatMessage{
|
||||
public final String sender;
|
||||
public final String message;
|
||||
public final String formattedMessage;
|
||||
|
||||
public ChatMessage(String message, String sender){
|
||||
this.message = message;
|
||||
this.sender = sender;
|
||||
if(sender == null){ //no sender, this is a server message?
|
||||
formattedMessage = message;
|
||||
}else{
|
||||
formattedMessage = "[CORAL][[" + sender + "[CORAL]]:[WHITE] " + message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
39
core/src/mindustry/ui/fragments/FadeInFragment.java
Normal file
39
core/src/mindustry/ui/fragments/FadeInFragment.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.*;
|
||||
import arc.scene.event.*;
|
||||
|
||||
/** Fades in a black overlay.*/
|
||||
public class FadeInFragment extends Fragment{
|
||||
private static final float duration = 40f;
|
||||
float time = 0f;
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
parent.addChild(new Element(){
|
||||
{
|
||||
setFillParent(true);
|
||||
touchable(Touchable.disabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.color(0f, 0f, 0f, Mathf.clamp(1f - time));
|
||||
Fill.crect(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta){
|
||||
super.act(delta);
|
||||
time += 1f / duration;
|
||||
if(time > 1){
|
||||
remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
7
core/src/mindustry/ui/fragments/Fragment.java
Normal file
7
core/src/mindustry/ui/fragments/Fragment.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.scene.Group;
|
||||
|
||||
public abstract class Fragment{
|
||||
public abstract void build(Group parent);
|
||||
}
|
||||
664
core/src/mindustry/ui/fragments/HudFragment.java
Normal file
664
core/src/mindustry/ui/fragments/HudFragment.java
Normal file
@@ -0,0 +1,664 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
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.ImageButton.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.ctype.ContentType;
|
||||
import mindustry.ctype.UnlockableContent;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.net.Packets.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.ui.Cicon;
|
||||
import mindustry.ui.dialogs.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class HudFragment extends Fragment{
|
||||
public final PlacementFragment blockfrag = new PlacementFragment();
|
||||
|
||||
private ImageButton flip;
|
||||
private Table lastUnlockTable;
|
||||
private Table lastUnlockLayout;
|
||||
private boolean shown = true;
|
||||
private float dsize = 47.2f;
|
||||
|
||||
private long lastToast;
|
||||
|
||||
public void build(Group parent){
|
||||
|
||||
//menu at top left
|
||||
parent.fill(cont -> {
|
||||
cont.setName("overlaymarker");
|
||||
cont.top().left();
|
||||
|
||||
if(mobile){
|
||||
|
||||
{
|
||||
Table select = new Table();
|
||||
|
||||
select.left();
|
||||
select.defaults().size(dsize).left();
|
||||
|
||||
ImageButtonStyle style = Styles.clearTransi;
|
||||
|
||||
select.addImageButton(Icon.menuLargeSmall, style, ui.paused::show);
|
||||
flip = select.addImageButton(Icon.arrowUpSmall, style, this::toggleMenus).get();
|
||||
|
||||
select.addImageButton(Icon.pasteSmall, style, ui.schematics::show);
|
||||
|
||||
select.addImageButton(Icon.pauseSmall, style, () -> {
|
||||
if(net.active()){
|
||||
ui.listfrag.toggle();
|
||||
}else{
|
||||
state.set(state.is(State.paused) ? State.playing : State.paused);
|
||||
}
|
||||
}).name("pause").update(i -> {
|
||||
if(net.active()){
|
||||
i.getStyle().imageUp = Icon.playersSmall;
|
||||
}else{
|
||||
i.setDisabled(false);
|
||||
i.getStyle().imageUp = state.is(State.paused) ? Icon.playSmall : Icon.pauseSmall;
|
||||
}
|
||||
});
|
||||
|
||||
select.addImageButton(Icon.chatSmall, style,() -> {
|
||||
if(net.active() && mobile){
|
||||
if(ui.chatfrag.shown()){
|
||||
ui.chatfrag.hide();
|
||||
}else{
|
||||
ui.chatfrag.toggle();
|
||||
}
|
||||
}else if(world.isZone()){
|
||||
ui.tech.show();
|
||||
}else{
|
||||
ui.database.show();
|
||||
}
|
||||
}).update(i -> {
|
||||
if(net.active() && mobile){
|
||||
i.getStyle().imageUp = Icon.chatSmall;
|
||||
}else{
|
||||
i.getStyle().imageUp = Icon.databaseSmall;
|
||||
}
|
||||
});
|
||||
|
||||
select.addImage().color(Pal.gray).width(4f).fillY();
|
||||
|
||||
float size = Scl.scl(dsize);
|
||||
Array<Element> children = new Array<>(select.getChildren());
|
||||
|
||||
//now, you may be wondering, why is this necessary? the answer is, I don't know, but it fixes layout issues somehow
|
||||
int index = 0;
|
||||
for(Element elem : children){
|
||||
int fi = index++;
|
||||
parent.addChild(elem);
|
||||
elem.visible(() -> {
|
||||
if(fi < 5){
|
||||
elem.setSize(size);
|
||||
}else{
|
||||
elem.setSize(Scl.scl(4f), size);
|
||||
}
|
||||
elem.setPosition(fi * size, Core.graphics.getHeight(), Align.topLeft);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
cont.add().size(dsize * 5 + 3, dsize).left();
|
||||
}
|
||||
|
||||
cont.row();
|
||||
cont.addImage().height(4f).color(Pal.gray).fillX();
|
||||
cont.row();
|
||||
}
|
||||
|
||||
cont.update(() -> {
|
||||
if(Core.input.keyTap(Binding.toggle_menus) && !ui.chatfrag.shown() && !Core.scene.hasDialog() && !(Core.scene.getKeyboardFocus() instanceof TextField)){
|
||||
toggleMenus();
|
||||
}
|
||||
});
|
||||
|
||||
Table wavesMain, editorMain;
|
||||
|
||||
cont.stack(wavesMain = new Table(), editorMain = new Table()).height(wavesMain.getPrefHeight());
|
||||
|
||||
{
|
||||
wavesMain.visible(() -> shown && !state.isEditor());
|
||||
wavesMain.top().left();
|
||||
Stack stack = new Stack();
|
||||
Button waves = new Button(Styles.waveb);
|
||||
Table btable = new Table().margin(0);
|
||||
|
||||
stack.add(waves);
|
||||
stack.add(btable);
|
||||
|
||||
addWaveTable(waves);
|
||||
addPlayButton(btable);
|
||||
wavesMain.add(stack).width(dsize * 5 + 4f);
|
||||
wavesMain.row();
|
||||
wavesMain.table(Tex.button, t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.white))
|
||||
.grow()).fillX().visible(() -> state.rules.waves && state.boss() != null).height(60f).get();
|
||||
wavesMain.row();
|
||||
}
|
||||
|
||||
{
|
||||
editorMain.table(Tex.buttonEdge4, t -> {
|
||||
//t.margin(0f);
|
||||
t.add("$editor.teams").growX().left();
|
||||
t.row();
|
||||
t.table(teams -> {
|
||||
teams.left();
|
||||
int i = 0;
|
||||
for(Team team : Team.all){
|
||||
ImageButton button = teams.addImageButton(Tex.whiteui, Styles.clearTogglePartiali, 40f, () -> Call.setPlayerTeamEditor(player, team))
|
||||
.size(50f).margin(6f).get();
|
||||
button.getImageCell().grow();
|
||||
button.getStyle().imageUpColor = team.color;
|
||||
button.update(() -> button.setChecked(player.getTeam() == team));
|
||||
|
||||
if(++i % 3 == 0){
|
||||
teams.row();
|
||||
}
|
||||
}
|
||||
}).left();
|
||||
|
||||
if(enableUnitEditing){
|
||||
|
||||
t.row();
|
||||
t.addImageTextButton("$editor.spawn", Icon.add, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("$editor.spawn");
|
||||
int i = 0;
|
||||
for(UnitType type : content.<UnitType>getBy(ContentType.unit)){
|
||||
dialog.cont.addImageButton(Tex.whiteui, 8 * 6f, () -> {
|
||||
Call.spawnUnitEditor(player, type);
|
||||
dialog.hide();
|
||||
}).get().getStyle().imageUp = new TextureRegionDrawable(type.icon(Cicon.xlarge));
|
||||
if(++i % 4 == 0) dialog.cont.row();
|
||||
}
|
||||
dialog.addCloseButton();
|
||||
dialog.setFillParent(false);
|
||||
dialog.show();
|
||||
}).fillX();
|
||||
|
||||
float[] size = {0};
|
||||
float[] position = {0, 0};
|
||||
|
||||
t.row();
|
||||
t.addImageTextButton("$editor.removeunit", Icon.quit, Styles.togglet, () -> {}).fillX().update(b -> {
|
||||
boolean[] found = {false};
|
||||
if(b.isChecked()){
|
||||
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(e == null){
|
||||
Vector2 world = Core.input.mouseWorld();
|
||||
Units.nearby(world.x, world.y, 1f, 1f, unit -> {
|
||||
if(!found[0] && unit instanceof BaseUnit){
|
||||
if(Core.input.keyTap(KeyCode.MOUSE_LEFT)){
|
||||
Call.removeUnitEditor(player, (BaseUnit)unit);
|
||||
}
|
||||
found[0] = true;
|
||||
unit.hitbox(Tmp.r1);
|
||||
size[0] = Mathf.lerpDelta(size[0], Tmp.r1.width * 2f + Mathf.absin(Time.time(), 10f, 5f), 0.1f);
|
||||
position[0] = unit.x;
|
||||
position[1] = unit.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Draw.color(Pal.accent, Color.white, Mathf.absin(Time.time(), 8f, 1f));
|
||||
Lines.poly(position[0], position[1], 4, size[0] / 2f);
|
||||
Draw.reset();
|
||||
|
||||
if(!found[0]){
|
||||
size[0] = Mathf.lerpDelta(size[0], 0f, 0.2f);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).width(dsize * 5 + 4f);
|
||||
editorMain.visible(() -> shown && state.isEditor());
|
||||
}
|
||||
|
||||
//fps display
|
||||
cont.table(info -> {
|
||||
info.top().left().margin(4).visible(() -> Core.settings.getBool("fps"));
|
||||
info.update(() -> info.setTranslation(state.rules.waves || state.isEditor() ? 0f : -Scl.scl(dsize * 4 + 3), 0));
|
||||
IntFormat fps = new IntFormat("fps");
|
||||
IntFormat ping = new IntFormat("ping");
|
||||
|
||||
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style(Styles.outlineLabel);
|
||||
info.row();
|
||||
info.label(() -> ping.get(netClient.getPing())).visible(net::client).left().style(Styles.outlineLabel);
|
||||
}).top().left();
|
||||
});
|
||||
|
||||
parent.fill(t -> {
|
||||
t.visible(() -> Core.settings.getBool("minimap") && !state.rules.tutorial);
|
||||
//minimap
|
||||
t.add(new Minimap());
|
||||
t.row();
|
||||
//position
|
||||
t.label(() -> world.toTile(player.x) + "," + world.toTile(player.y))
|
||||
.visible(() -> Core.settings.getBool("position") && !state.rules.tutorial);
|
||||
t.top().right();
|
||||
});
|
||||
|
||||
//spawner warning
|
||||
parent.fill(t -> {
|
||||
t.touchable(Touchable.disabled);
|
||||
t.table(Styles.black, c -> c.add("$nearpoint")
|
||||
.update(l -> l.setColor(Tmp.c1.set(Color.white).lerp(Color.scarlet, Mathf.absin(Time.time(), 10f, 1f))))
|
||||
.get().setAlignment(Align.center, Align.center))
|
||||
.margin(6).update(u -> u.color.a = Mathf.lerpDelta(u.color.a, Mathf.num(spawner.playerNear()), 0.1f)).get().color.a = 0f;
|
||||
});
|
||||
|
||||
parent.fill(t -> {
|
||||
t.visible(() -> netServer.isWaitingForPlayers());
|
||||
t.table(Tex.button, c -> c.add("$waiting.players"));
|
||||
});
|
||||
|
||||
//'core is under attack' table
|
||||
parent.fill(t -> {
|
||||
t.touchable(Touchable.disabled);
|
||||
float notifDuration = 240f;
|
||||
float[] coreAttackTime = {0};
|
||||
float[] coreAttackOpacity = {0};
|
||||
|
||||
Events.on(Trigger.teamCoreDamage, () -> {
|
||||
coreAttackTime[0] = notifDuration;
|
||||
});
|
||||
|
||||
t.top().visible(() -> {
|
||||
if(state.is(State.menu) || state.teams.get(player.getTeam()).cores.size == 0 || state.teams.get(player.getTeam()).cores.first().entity == null){
|
||||
coreAttackTime[0] = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
t.getColor().a = coreAttackOpacity[0];
|
||||
if(coreAttackTime[0] > 0){
|
||||
coreAttackOpacity[0] = Mathf.lerpDelta(coreAttackOpacity[0], 1f, 0.1f);
|
||||
}else{
|
||||
coreAttackOpacity[0] = Mathf.lerpDelta(coreAttackOpacity[0], 0f, 0.1f);
|
||||
}
|
||||
|
||||
coreAttackTime[0] -= Time.delta();
|
||||
|
||||
return coreAttackOpacity[0] > 0;
|
||||
});
|
||||
t.table(Tex.button, top -> top.add("$coreattack").pad(2)
|
||||
.update(label -> label.getColor().set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
|
||||
});
|
||||
|
||||
//tutorial text
|
||||
parent.fill(t -> {
|
||||
Runnable resize = () -> {
|
||||
t.clearChildren();
|
||||
t.top().right().visible(() -> state.rules.tutorial);
|
||||
t.stack(new Button(){{
|
||||
marginLeft(48f);
|
||||
labelWrap(() -> control.tutorial.stage.text() + (control.tutorial.canNext() ? "\n\n" + Core.bundle.get("tutorial.next") : "")).width(!Core.graphics.isPortrait() ? 400f : 160f).pad(2f);
|
||||
clicked(() -> control.tutorial.nextSentence());
|
||||
setDisabled(() -> !control.tutorial.canNext());
|
||||
}},
|
||||
new Table(f -> {
|
||||
f.left().addImageButton(Icon.arrowLeftSmall, Styles.emptyi, () -> {
|
||||
control.tutorial.prevSentence();
|
||||
}).width(44f).growY().visible(() -> control.tutorial.canPrev());
|
||||
}));
|
||||
};
|
||||
|
||||
resize.run();
|
||||
Events.on(ResizeEvent.class, e -> resize.run());
|
||||
});
|
||||
|
||||
//paused table
|
||||
parent.fill(t -> {
|
||||
t.top().visible(() -> state.isPaused()).touchable(Touchable.disabled);
|
||||
t.table(Tex.buttonTrans, top -> top.add("$paused").pad(5f));
|
||||
});
|
||||
|
||||
//'saving' indicator
|
||||
parent.fill(t -> {
|
||||
t.bottom().visible(() -> control.saves.isSaving());
|
||||
t.add("$saveload").style(Styles.outlineLabel);
|
||||
});
|
||||
|
||||
blockfrag.build(parent);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, forward = true, called = Loc.both)
|
||||
public static void setPlayerTeamEditor(Player player, Team team){
|
||||
if(state.isEditor() && player != null){
|
||||
player.setTeam(team);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server)
|
||||
public static void spawnUnitEditor(Player player, UnitType type){
|
||||
if(state.isEditor()){
|
||||
BaseUnit unit = type.create(player.getTeam());
|
||||
unit.set(player.x, player.y);
|
||||
unit.rotation = player.rotation;
|
||||
unit.add();
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void removeUnitEditor(Player player, BaseUnit unit){
|
||||
if(state.isEditor() && unit != null){
|
||||
unit.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleToast(Runnable run){
|
||||
long duration = (int)(3.5 * 1000);
|
||||
long since = Time.timeSinceMillis(lastToast);
|
||||
if(since > duration){
|
||||
lastToast = Time.millis();
|
||||
run.run();
|
||||
}else{
|
||||
Time.runTask((duration - since) / 1000f * 60f, run);
|
||||
lastToast += duration;
|
||||
}
|
||||
}
|
||||
|
||||
public void showToast(String text){
|
||||
if(state.is(State.menu)) return;
|
||||
|
||||
scheduleToast(() -> {
|
||||
Sounds.message.play();
|
||||
|
||||
Table table = new Table(Tex.button);
|
||||
table.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
table.remove();
|
||||
}
|
||||
});
|
||||
table.margin(12);
|
||||
table.addImage(Icon.check).pad(3);
|
||||
table.add(text).wrap().width(280f).get().setAlignment(Align.center, Align.center);
|
||||
table.pack();
|
||||
|
||||
//create container table which will align and move
|
||||
Table container = Core.scene.table();
|
||||
container.top().add(table);
|
||||
container.setTranslation(0, table.getPrefHeight());
|
||||
container.actions(Actions.translateBy(0, -table.getPrefHeight(), 1f, Interpolation.fade), Actions.delay(2.5f),
|
||||
//nesting actions() calls is necessary so the right prefHeight() is used
|
||||
Actions.run(() -> container.actions(Actions.translateBy(0, table.getPrefHeight(), 1f, Interpolation.fade), Actions.remove())));
|
||||
});
|
||||
}
|
||||
|
||||
public boolean shown(){
|
||||
return shown;
|
||||
}
|
||||
|
||||
/** Show unlock notification for a new recipe. */
|
||||
public void showUnlock(UnlockableContent content){
|
||||
//some content may not have icons... yet
|
||||
//also don't play in the tutorial to prevent confusion
|
||||
if(state.is(State.menu) || state.rules.tutorial) return;
|
||||
|
||||
Sounds.message.play();
|
||||
|
||||
//if there's currently no unlock notification...
|
||||
if(lastUnlockTable == null){
|
||||
scheduleToast(() -> {
|
||||
Table table = new Table(Tex.button);
|
||||
table.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
table.remove();
|
||||
lastUnlockLayout = null;
|
||||
lastUnlockTable = null;
|
||||
}
|
||||
});
|
||||
table.margin(12);
|
||||
|
||||
Table in = new Table();
|
||||
|
||||
//create texture stack for displaying
|
||||
Image image = new Image(content.icon(Cicon.xlarge));
|
||||
image.setScaling(Scaling.fit);
|
||||
|
||||
in.add(image).size(8 * 6).pad(2);
|
||||
|
||||
//add to table
|
||||
table.add(in).padRight(8);
|
||||
table.add("$unlocked");
|
||||
table.pack();
|
||||
|
||||
//create container table which will align and move
|
||||
Table container = Core.scene.table();
|
||||
container.top().add(table);
|
||||
container.setTranslation(0, table.getPrefHeight());
|
||||
container.actions(Actions.translateBy(0, -table.getPrefHeight(), 1f, Interpolation.fade), Actions.delay(2.5f),
|
||||
//nesting actions() calls is necessary so the right prefHeight() is used
|
||||
Actions.run(() -> container.actions(Actions.translateBy(0, table.getPrefHeight(), 1f, Interpolation.fade), Actions.run(() -> {
|
||||
lastUnlockTable = null;
|
||||
lastUnlockLayout = null;
|
||||
}), Actions.remove())));
|
||||
|
||||
lastUnlockTable = container;
|
||||
lastUnlockLayout = in;
|
||||
});
|
||||
}else{
|
||||
//max column size
|
||||
int col = 3;
|
||||
//max amount of elements minus extra 'plus'
|
||||
int cap = col * col - 1;
|
||||
|
||||
//get old elements
|
||||
Array<Element> elements = new Array<>(lastUnlockLayout.getChildren());
|
||||
int esize = elements.size;
|
||||
|
||||
//...if it's already reached the cap, ignore everything
|
||||
if(esize > cap) return;
|
||||
|
||||
//get size of each element
|
||||
float size = 48f / Math.min(elements.size + 1, col);
|
||||
|
||||
lastUnlockLayout.clearChildren();
|
||||
lastUnlockLayout.defaults().size(size).pad(2);
|
||||
|
||||
for(int i = 0; i < esize; i++){
|
||||
lastUnlockLayout.add(elements.get(i));
|
||||
|
||||
if(i % col == col - 1){
|
||||
lastUnlockLayout.row();
|
||||
}
|
||||
}
|
||||
|
||||
//if there's space, add it
|
||||
if(esize < cap){
|
||||
|
||||
Image image = new Image(content.icon(Cicon.medium));
|
||||
image.setScaling(Scaling.fit);
|
||||
|
||||
lastUnlockLayout.add(image);
|
||||
}else{ //else, add a specific icon to denote no more space
|
||||
lastUnlockLayout.addImage(Icon.add);
|
||||
}
|
||||
|
||||
lastUnlockLayout.pack();
|
||||
}
|
||||
}
|
||||
|
||||
public void showLaunch(){
|
||||
Image image = new Image();
|
||||
image.getColor().a = 0f;
|
||||
image.setFillParent(true);
|
||||
image.actions(Actions.fadeIn(40f / 60f));
|
||||
image.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
image.remove();
|
||||
}
|
||||
});
|
||||
Core.scene.add(image);
|
||||
}
|
||||
|
||||
public void showLand(){
|
||||
Image image = new Image();
|
||||
image.getColor().a = 1f;
|
||||
image.touchable(Touchable.disabled);
|
||||
image.setFillParent(true);
|
||||
image.actions(Actions.fadeOut(0.8f), Actions.remove());
|
||||
image.update(() -> {
|
||||
image.toFront();
|
||||
if(state.is(State.menu)){
|
||||
image.remove();
|
||||
}
|
||||
});
|
||||
Core.scene.add(image);
|
||||
}
|
||||
|
||||
private void showLaunchConfirm(){
|
||||
FloatingDialog dialog = new FloatingDialog("$launch");
|
||||
dialog.update(() -> {
|
||||
if(!inLaunchWave()){
|
||||
dialog.hide();
|
||||
}
|
||||
});
|
||||
dialog.cont.add("$launch.confirm").width(500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.buttons.defaults().size(200f, 54f).pad(2f);
|
||||
dialog.setFillParent(false);
|
||||
dialog.buttons.addButton("$cancel", dialog::hide);
|
||||
dialog.buttons.addButton("$ok", () -> {
|
||||
dialog.hide();
|
||||
Call.launchZone();
|
||||
});
|
||||
dialog.keyDown(KeyCode.ESCAPE, dialog::hide);
|
||||
dialog.keyDown(KeyCode.BACK, dialog::hide);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private boolean inLaunchWave(){
|
||||
return world.isZone() &&
|
||||
world.getZone().metCondition() &&
|
||||
!net.client() &&
|
||||
state.wave % world.getZone().launchPeriod == 0 && !spawner.isSpawning();
|
||||
}
|
||||
|
||||
private boolean canLaunch(){
|
||||
return inLaunchWave() && state.enemies() <= 0;
|
||||
}
|
||||
|
||||
private void toggleMenus(){
|
||||
if(flip != null){
|
||||
flip.getStyle().imageUp = shown ? Icon.arrowDownSmall : Icon.arrowUpSmall;
|
||||
}
|
||||
|
||||
shown = !shown;
|
||||
}
|
||||
|
||||
private void addWaveTable(Button table){
|
||||
StringBuilder ibuild = new StringBuilder();
|
||||
|
||||
IntFormat wavef = new IntFormat("wave");
|
||||
IntFormat enemyf = new IntFormat("wave.enemy");
|
||||
IntFormat enemiesf = new IntFormat("wave.enemies");
|
||||
IntFormat waitingf = new IntFormat("wave.waiting", i -> {
|
||||
ibuild.setLength(0);
|
||||
int m = i/60;
|
||||
int s = i % 60;
|
||||
if(m <= 0){
|
||||
ibuild.append(s);
|
||||
}else{
|
||||
ibuild.append(m);
|
||||
ibuild.append(":");
|
||||
if(s < 10){
|
||||
ibuild.append("0");
|
||||
}
|
||||
ibuild.append(s);
|
||||
}
|
||||
return ibuild.toString();
|
||||
});
|
||||
|
||||
table.clearChildren();
|
||||
table.touchable(Touchable.enabled);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
table.setName("waves");
|
||||
table.labelWrap(() -> {
|
||||
builder.setLength(0);
|
||||
builder.append(wavef.get(state.wave));
|
||||
builder.append("\n");
|
||||
|
||||
if(inLaunchWave()){
|
||||
builder.append("[#");
|
||||
Tmp.c1.set(Color.white).lerp(state.enemies() > 0 ? Color.white : Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)).toString(builder);
|
||||
builder.append("]");
|
||||
|
||||
if(!canLaunch()){
|
||||
builder.append(Core.bundle.get("launch.unable2"));
|
||||
}else{
|
||||
builder.append(Core.bundle.get("launch"));
|
||||
builder.append("\n");
|
||||
builder.append(Core.bundle.format("launch.next", state.wave + world.getZone().launchPeriod));
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append("[]\n");
|
||||
}
|
||||
|
||||
if(state.enemies() > 0){
|
||||
if(state.enemies() == 1){
|
||||
builder.append(enemyf.get(state.enemies()));
|
||||
}else{
|
||||
builder.append(enemiesf.get(state.enemies()));
|
||||
}
|
||||
builder.append("\n");
|
||||
}
|
||||
|
||||
if(state.rules.waveTimer){
|
||||
builder.append((state.rules.waitForWaveToEnd && unitGroups[waveTeam.ordinal()].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60))));
|
||||
}else if(state.enemies() == 0){
|
||||
builder.append(Core.bundle.get("waiting"));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}).growX().pad(8f);
|
||||
|
||||
table.setDisabled(() -> !canLaunch());
|
||||
table.visible(() -> state.rules.waves);
|
||||
table.clicked(() -> {
|
||||
if(canLaunch()){
|
||||
showLaunchConfirm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean canSkipWave(){
|
||||
return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial;
|
||||
}
|
||||
|
||||
private void addPlayButton(Table table){
|
||||
table.right().addImageButton(Icon.playSmaller, Styles.righti, 30f, () -> {
|
||||
if(net.client() && player.isAdmin){
|
||||
Call.onAdminRequest(player, AdminAction.wave);
|
||||
}else if(inLaunchWave()){
|
||||
ui.showConfirm("$confirm", "$launch.skip.confirm", () -> !canSkipWave(), () -> state.wavetime = 0f);
|
||||
}else{
|
||||
state.wavetime = 0f;
|
||||
}
|
||||
}).growY().fillX().right().width(40f)
|
||||
.visible(this::canSkipWave);
|
||||
}
|
||||
}
|
||||
77
core/src/mindustry/ui/fragments/LoadingFragment.java
Normal file
77
core/src/mindustry/ui/fragments/LoadingFragment.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.scene.Group;
|
||||
import arc.scene.actions.*;
|
||||
import arc.scene.event.Touchable;
|
||||
import arc.scene.ui.Label;
|
||||
import arc.scene.ui.TextButton;
|
||||
import arc.scene.ui.layout.Table;
|
||||
import mindustry.graphics.Pal;
|
||||
import mindustry.ui.*;
|
||||
|
||||
public class LoadingFragment extends Fragment{
|
||||
private Table table;
|
||||
private TextButton button;
|
||||
private Bar bar;
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
parent.fill(Styles.black8, t -> {
|
||||
t.visible(false);
|
||||
t.touchable(Touchable.enabled);
|
||||
t.add().height(133f).row();
|
||||
t.addImage().growX().height(3f).pad(4f).growX().get().setColor(Pal.accent);
|
||||
t.row();
|
||||
t.add("$loading").name("namelabel").pad(10f);
|
||||
t.row();
|
||||
t.addImage().growX().height(3f).pad(4f).growX().get().setColor(Pal.accent);
|
||||
t.row();
|
||||
|
||||
bar = t.add(new Bar()).pad(3).size(500f, 40f).visible(false).get();
|
||||
t.row();
|
||||
button = t.addButton("$cancel", () -> {}).pad(20).size(250f, 70f).visible(false).get();
|
||||
table = t;
|
||||
});
|
||||
}
|
||||
|
||||
public void setProgress(Floatp progress){
|
||||
bar.reset(0f);
|
||||
bar.visible(true);
|
||||
bar.set(() -> ((int)(progress.get() * 100) + "%"), progress, Pal.accent);
|
||||
}
|
||||
|
||||
public void setButton(Runnable listener){
|
||||
button.visible(true);
|
||||
button.getListeners().remove(button.getListeners().size - 1);
|
||||
button.clicked(listener);
|
||||
}
|
||||
|
||||
public void setText(String text){
|
||||
table.<Label>find("namelabel").setText(text);
|
||||
table.<Label>find("namelabel").setColor(Pal.accent);
|
||||
}
|
||||
|
||||
public void show(){
|
||||
show("$loading");
|
||||
}
|
||||
|
||||
public void show(String text){
|
||||
table.<Label>find("namelabel").setColor(Color.white);
|
||||
bar.visible(false);
|
||||
table.clearActions();
|
||||
table.touchable(Touchable.enabled);
|
||||
table.<Label>find("namelabel").setText(text);
|
||||
table.visible(true);
|
||||
table.getColor().a = 1f;
|
||||
table.toFront();
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
table.clearActions();
|
||||
table.toFront();
|
||||
table.touchable(Touchable.disabled);
|
||||
table.actions(Actions.fadeOut(0.5f), Actions.visible(false));
|
||||
}
|
||||
}
|
||||
255
core/src/mindustry/ui/fragments/MenuFragment.java
Normal file
255
core/src/mindustry/ui/fragments/MenuFragment.java
Normal file
@@ -0,0 +1,255 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
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.core.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class MenuFragment extends Fragment{
|
||||
private Table container, submenu;
|
||||
private Button currentMenu;
|
||||
private MenuRenderer renderer;
|
||||
|
||||
public MenuFragment(){
|
||||
Events.on(DisposeEvent.class, event -> {
|
||||
renderer.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
renderer = new MenuRenderer();
|
||||
|
||||
Group group = new WidgetGroup();
|
||||
group.setFillParent(true);
|
||||
group.visible(() -> !ui.editor.isShown());
|
||||
parent.addChild(group);
|
||||
|
||||
parent = group;
|
||||
|
||||
parent.fill((x, y, w, h) -> renderer.render());
|
||||
|
||||
parent.fill(c -> {
|
||||
container = c;
|
||||
|
||||
if(!mobile){
|
||||
buildDesktop();
|
||||
Events.on(ResizeEvent.class, event -> buildDesktop());
|
||||
}else{
|
||||
buildMobile();
|
||||
Events.on(ResizeEvent.class, event -> buildMobile());
|
||||
}
|
||||
});
|
||||
|
||||
//info icon
|
||||
if(mobile){
|
||||
parent.fill(c -> c.bottom().left().addButton("", Styles.infot, ui.about::show).size(84, 45));
|
||||
parent.fill(c -> c.bottom().right().addButton("", Styles.discordt, ui.discord::show).size(84, 45));
|
||||
}
|
||||
|
||||
String versionText = "[#ffffffba]" + ((Version.build == -1) ? "[#fc8140aa]custom build" : (Version.type.equals("official") ? Version.modifier : Version.type) + " build " + Version.build + (Version.revision == 0 ? "" : "." + Version.revision));
|
||||
|
||||
parent.fill((x, y, w, h) -> {
|
||||
TextureRegion logo = Core.atlas.find("logo");
|
||||
float logoscl = Scl.scl(1);
|
||||
float logow = Math.min(logo.getWidth() * logoscl, Core.graphics.getWidth() - Scl.scl(20));
|
||||
float logoh = logow * (float)logo.getHeight() / logo.getWidth();
|
||||
|
||||
float fx = (int)(Core.graphics.getWidth() / 2f);
|
||||
float fy = (int)(Core.graphics.getHeight() - 6 - logoh) + logoh / 2 - (Core.graphics.isPortrait() ? Scl.scl(30f) : 0f);
|
||||
|
||||
Draw.color();
|
||||
Draw.rect(logo, fx, fy, logow, logoh);
|
||||
|
||||
Fonts.def.setColor(Color.white);
|
||||
Fonts.def.draw(versionText, fx, fy - logoh/2f, Align.center);
|
||||
}).touchable(Touchable.disabled);
|
||||
}
|
||||
|
||||
private void buildMobile(){
|
||||
container.clear();
|
||||
container.setSize(Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
|
||||
float size = 120f;
|
||||
container.defaults().size(size).pad(5).padTop(4f);
|
||||
|
||||
MobileButton
|
||||
play = new MobileButton(Icon.play2, "$campaign", () -> checkPlay(ui.deploy::show)),
|
||||
custom = new MobileButton(Icon.playCustom, "$customgame", () -> checkPlay(ui.custom::show)),
|
||||
maps = new MobileButton(Icon.load, "$loadgame", () -> checkPlay(ui.load::show)),
|
||||
join = new MobileButton(Icon.add, "$joingame", () -> checkPlay(ui.join::show)),
|
||||
editor = new MobileButton(Icon.editor, "$editor", () -> checkPlay(ui.maps::show)),
|
||||
tools = new MobileButton(Icon.tools, "$settings", ui.settings::show),
|
||||
mods = new MobileButton(Icon.wiki, "$mods", ui.mods::show),
|
||||
donate = new MobileButton(Icon.link, "$website", () -> Core.net.openURI("https://anuke.itch.io/mindustry")),
|
||||
exit = new MobileButton(Icon.exit, "$quit", () -> Core.app.exit());
|
||||
|
||||
if(!Core.graphics.isPortrait()){
|
||||
container.marginTop(60f);
|
||||
container.add(play);
|
||||
container.add(join);
|
||||
container.add(custom);
|
||||
container.add(maps);
|
||||
container.row();
|
||||
|
||||
container.table(table -> {
|
||||
table.defaults().set(container.defaults());
|
||||
|
||||
table.add(editor);
|
||||
table.add(tools);
|
||||
|
||||
table.add(mods);
|
||||
//if(platform.canDonate()) table.add(donate);
|
||||
if(!ios) table.add(exit);
|
||||
}).colspan(4);
|
||||
}else{
|
||||
container.marginTop(0f);
|
||||
container.add(play);
|
||||
container.add(maps);
|
||||
container.row();
|
||||
container.add(custom);
|
||||
container.add(join);
|
||||
container.row();
|
||||
container.add(editor);
|
||||
container.add(tools);
|
||||
container.row();
|
||||
|
||||
container.table(table -> {
|
||||
table.defaults().set(container.defaults());
|
||||
|
||||
table.add(mods);
|
||||
//if(platform.canDonate()) table.add(donate);
|
||||
if(!ios) table.add(exit);
|
||||
}).colspan(2);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildDesktop(){
|
||||
container.clear();
|
||||
container.setSize(Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
|
||||
|
||||
float width = 230f;
|
||||
Drawable background = Styles.black6;
|
||||
|
||||
container.left();
|
||||
container.add().width(Core.graphics.getWidth()/10f);
|
||||
container.table(background, t -> {
|
||||
t.defaults().width(width).height(70f);
|
||||
|
||||
buttons(t,
|
||||
new Buttoni("$play", Icon.play2Small,
|
||||
new Buttoni("$campaign", Icon.play2Small, () -> checkPlay(ui.deploy::show)),
|
||||
new Buttoni("$joingame", Icon.addSmall, () -> checkPlay(ui.join::show)),
|
||||
new Buttoni("$customgame", Icon.editorSmall, () -> checkPlay(ui.custom::show)),
|
||||
new Buttoni("$loadgame", Icon.loadSmall, () -> checkPlay(ui.load::show)),
|
||||
new Buttoni("$tutorial", Icon.infoSmall, () -> checkPlay(control::playTutorial))
|
||||
),
|
||||
new Buttoni("$editor", Icon.editorSmall, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null,
|
||||
new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show),
|
||||
//not enough space for this button
|
||||
//new Buttoni("$schematics", Icon.pasteSmall, ui.schematics::show),
|
||||
new Buttoni("$settings", Icon.toolsSmall, ui.settings::show),
|
||||
new Buttoni("$about.button", Icon.infoSmall, ui.about::show),
|
||||
new Buttoni("$quit", Icon.exitSmall, Core.app::exit)
|
||||
);
|
||||
|
||||
}).width(width).growY();
|
||||
|
||||
container.table(background, t -> {
|
||||
submenu = t;
|
||||
t.getColor().a = 0f;
|
||||
t.top();
|
||||
t.defaults().width(width).height(70f);
|
||||
t.visible(() -> !t.getChildren().isEmpty());
|
||||
|
||||
}).width(width).growY();
|
||||
}
|
||||
|
||||
private void checkPlay(Runnable run){
|
||||
if(!mods.hasContentErrors()){
|
||||
run.run();
|
||||
}else{
|
||||
ui.showInfo("$mod.noerrorplay");
|
||||
}
|
||||
}
|
||||
|
||||
private void fadeInMenu(){
|
||||
submenu.clearActions();
|
||||
submenu.actions(Actions.alpha(1f, 0.15f, Interpolation.fade));
|
||||
}
|
||||
|
||||
private void fadeOutMenu(){
|
||||
//nothing to fade out
|
||||
if(submenu.getChildren().isEmpty()){
|
||||
return;
|
||||
}
|
||||
|
||||
submenu.clearActions();
|
||||
submenu.actions(Actions.alpha(1f), Actions.alpha(0f, 0.2f, Interpolation.fade), Actions.run(() -> submenu.clearChildren()));
|
||||
}
|
||||
|
||||
private void buttons(Table t, Buttoni... buttons){
|
||||
for(Buttoni b : buttons){
|
||||
if(b == null) continue;
|
||||
Button[] out = {null};
|
||||
out[0] = t.addImageTextButton(b.text, b.icon, Styles.clearToggleMenut, () -> {
|
||||
if(currentMenu == out[0]){
|
||||
currentMenu = null;
|
||||
fadeOutMenu();
|
||||
}else{
|
||||
if(b.submenu != null){
|
||||
currentMenu = out[0];
|
||||
submenu.clearChildren();
|
||||
fadeInMenu();
|
||||
//correctly offset the button
|
||||
submenu.add().height((Core.graphics.getHeight() - out[0].getY(Align.topLeft)) / Scl.scl(1f));
|
||||
submenu.row();
|
||||
buttons(submenu, b.submenu);
|
||||
}else{
|
||||
currentMenu = null;
|
||||
fadeOutMenu();
|
||||
b.runnable.run();
|
||||
}
|
||||
}
|
||||
}).marginLeft(11f).get();
|
||||
out[0].update(() -> out[0].setChecked(currentMenu == out[0]));
|
||||
t.row();
|
||||
}
|
||||
}
|
||||
|
||||
private class Buttoni{
|
||||
final Drawable icon;
|
||||
final String text;
|
||||
final Runnable runnable;
|
||||
final Buttoni[] submenu;
|
||||
|
||||
public Buttoni(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){
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
this.runnable = () -> {};
|
||||
this.submenu = buttons;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
core/src/mindustry/ui/fragments/OverlayFragment.java
Normal file
32
core/src/mindustry/ui/fragments/OverlayFragment.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.scene.event.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import mindustry.*;
|
||||
|
||||
/** Fragment for displaying overlays such as block inventories. */
|
||||
public class OverlayFragment{
|
||||
public final BlockInventoryFragment inv;
|
||||
public final BlockConfigFragment config;
|
||||
|
||||
private WidgetGroup group = new WidgetGroup();
|
||||
|
||||
public OverlayFragment(){
|
||||
group.touchable(Touchable.childrenOnly);
|
||||
inv = new BlockInventoryFragment();
|
||||
config = new BlockConfigFragment();
|
||||
}
|
||||
|
||||
public void add(){
|
||||
group.setFillParent(true);
|
||||
Vars.ui.hudGroup.addChildBefore(Core.scene.find("overlaymarker"), group);
|
||||
|
||||
inv.build(group);
|
||||
config.build(group);
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
group.remove();
|
||||
}
|
||||
}
|
||||
467
core/src/mindustry/ui/fragments/PlacementFragment.java
Normal file
467
core/src/mindustry/ui/fragments/PlacementFragment.java
Normal file
@@ -0,0 +1,467 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
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.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.traits.BuilderTrait.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.ui.Cicon;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class PlacementFragment extends Fragment{
|
||||
final int rowWidth = 4;
|
||||
|
||||
public Category currentCategory = Category.distribution;
|
||||
Array<Block> returnArray = new Array<>();
|
||||
Array<Category> returnCatArray = new Array<>();
|
||||
boolean[] categoryEmpty = new boolean[Category.all.length];
|
||||
ObjectMap<Category,Block> selectedBlocks = new ObjectMap<Category,Block>();
|
||||
Block hovered, lastDisplay;
|
||||
Tile lastHover;
|
||||
Tile hoverTile;
|
||||
Table blockTable, toggler, topTable;
|
||||
boolean lastGround;
|
||||
boolean blockSelectEnd;
|
||||
int blockSelectSeq;
|
||||
long blockSelectSeqMillis;
|
||||
Binding[] blockSelect = {
|
||||
Binding.block_select_01,
|
||||
Binding.block_select_02,
|
||||
Binding.block_select_03,
|
||||
Binding.block_select_04,
|
||||
Binding.block_select_05,
|
||||
Binding.block_select_06,
|
||||
Binding.block_select_07,
|
||||
Binding.block_select_08,
|
||||
Binding.block_select_09,
|
||||
Binding.block_select_10,
|
||||
Binding.block_select_left,
|
||||
Binding.block_select_right,
|
||||
Binding.block_select_up,
|
||||
Binding.block_select_down
|
||||
};
|
||||
|
||||
public PlacementFragment(){
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
Core.app.post(() -> {
|
||||
control.input.block = null;
|
||||
rebuild();
|
||||
});
|
||||
});
|
||||
|
||||
Events.on(UnlockEvent.class, event -> {
|
||||
if(event.content instanceof Block){
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(ResetEvent.class, event -> {
|
||||
selectedBlocks.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
currentCategory = Category.turret;
|
||||
Group group = toggler.getParent();
|
||||
int index = toggler.getZIndex();
|
||||
toggler.remove();
|
||||
build(group);
|
||||
toggler.setZIndex(index);
|
||||
}
|
||||
|
||||
boolean gridUpdate(InputHandler input){
|
||||
if(Core.input.keyDown(Binding.pick)){ //mouse eyedropper select
|
||||
Tile tile = world.ltileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
Block tryRecipe = tile == null ? null : tile.block();
|
||||
|
||||
for(BuildRequest req : player.buildQueue()){
|
||||
if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){
|
||||
tryRecipe = req.block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(tryRecipe != null && tryRecipe.isVisible() && unlocked(tryRecipe)){
|
||||
input.block = tryRecipe;
|
||||
currentCategory = input.block.category;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(ui.chatfrag.shown() || Core.scene.hasKeyboard()) return false;
|
||||
|
||||
for(int i = 0; i < blockSelect.length; i++){
|
||||
if(Core.input.keyTap(blockSelect[i])){
|
||||
if(i > 9) { //select block directionally
|
||||
Array<Block> blocks = getByCategory(currentCategory);
|
||||
Block currentBlock = getSelectedBlock(currentCategory);
|
||||
for(int j = 0; j < blocks.size; j++){
|
||||
if(blocks.get(j) == currentBlock){
|
||||
switch(i){
|
||||
case 10: //left
|
||||
j = (j - 1 + blocks.size) % blocks.size;
|
||||
break;
|
||||
case 11: //right
|
||||
j = (j + 1) % blocks.size;
|
||||
break;
|
||||
case 12: //up
|
||||
j = (j > 3 ? j - 4 : blocks.size - blocks.size % 4 + j);
|
||||
j -= (j < blocks.size ? 0 : 4);
|
||||
break;
|
||||
case 13: //down
|
||||
j = (j < blocks.size - 4 ? j + 4 : j % 4);
|
||||
}
|
||||
input.block = blocks.get(j);
|
||||
selectedBlocks.put(currentCategory, input.block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(blockSelectEnd || Time.timeSinceMillis(blockSelectSeqMillis) > Core.settings.getInt("blockselecttimeout")){ //1st number of combo, select category
|
||||
//select only visible categories
|
||||
if(!getByCategory(Category.all[i]).isEmpty()){
|
||||
currentCategory = Category.all[i];
|
||||
if(input.block != null){
|
||||
input.block = getSelectedBlock(currentCategory);
|
||||
}
|
||||
blockSelectEnd = false;
|
||||
blockSelectSeq = 0;
|
||||
blockSelectSeqMillis = Time.millis();
|
||||
}
|
||||
}else{ //select block
|
||||
if(blockSelectSeq == 0){ //2nd number of combo
|
||||
blockSelectSeq = i + 1;
|
||||
}else{ //3rd number of combo
|
||||
//entering "X,1,0" selects the same block as "X,0"
|
||||
i += (blockSelectSeq - (i != 9 ? 0 : 1)) * 10;
|
||||
blockSelectEnd = true;
|
||||
}
|
||||
Array<Block> blocks = getByCategory(currentCategory);
|
||||
input.block = (i < blocks.size) ? blocks.get(i) : null;
|
||||
selectedBlocks.put(currentCategory, input.block);
|
||||
blockSelectSeqMillis = Time.millis();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.category_prev)){
|
||||
do{
|
||||
currentCategory = currentCategory.prev();
|
||||
}while(categoryEmpty[currentCategory.ordinal()]);
|
||||
input.block = getSelectedBlock(currentCategory);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.category_next)){
|
||||
do{
|
||||
currentCategory = currentCategory.next();
|
||||
}while(categoryEmpty[currentCategory.ordinal()]);
|
||||
input.block = getSelectedBlock(currentCategory);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
parent.fill(full -> {
|
||||
toggler = full;
|
||||
full.bottom().right().visible(() -> ui.hudfrag.shown());
|
||||
|
||||
full.table(frame -> {
|
||||
|
||||
//rebuilds the category table with the correct recipes
|
||||
Runnable rebuildCategory = () -> {
|
||||
blockTable.clear();
|
||||
blockTable.top().margin(5);
|
||||
|
||||
int index = 0;
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
group.setMinCheckCount(0);
|
||||
|
||||
for(Block block : getByCategory(currentCategory)){
|
||||
if(index++ % rowWidth == 0){
|
||||
blockTable.row();
|
||||
}
|
||||
|
||||
ImageButton button = blockTable.addImageButton(Icon.lockedSmall, Styles.selecti, () -> {
|
||||
if(unlocked(block)){
|
||||
control.input.block = control.input.block == block ? null : block;
|
||||
selectedBlocks.put(currentCategory, control.input.block);
|
||||
}
|
||||
}).size(46f).group(group).name("block-" + block.name).get();
|
||||
|
||||
button.getStyle().imageUp = new TextureRegionDrawable(block.icon(Cicon.medium));
|
||||
|
||||
button.update(() -> { //color unplacable things gray
|
||||
TileEntity core = player.getClosestCore();
|
||||
Color color = state.rules.infiniteResources || (core != null && (core.items.has(block.requirements, state.rules.buildCostMultiplier) || state.rules.infiniteResources)) ? Color.white : Color.gray;
|
||||
button.forEach(elem -> elem.setColor(color));
|
||||
button.setChecked(control.input.block == block);
|
||||
|
||||
if(state.rules.bannedBlocks.contains(block)){
|
||||
button.forEach(elem -> elem.setColor(Color.darkGray));
|
||||
}
|
||||
});
|
||||
|
||||
button.hovered(() -> hovered = block);
|
||||
button.exited(() -> {
|
||||
if(hovered == block){
|
||||
hovered = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
//add missing elements to even out table size
|
||||
if(index < 4){
|
||||
for(int i = 0; i < 4-index; i++){
|
||||
blockTable.add().size(46f);
|
||||
}
|
||||
}
|
||||
blockTable.act(0f);
|
||||
};
|
||||
|
||||
//top table with hover info
|
||||
frame.table(Tex.buttonEdge2,top -> {
|
||||
topTable = top;
|
||||
top.add(new Table()).growX().update(topTable -> {
|
||||
//don't refresh unnecessarily
|
||||
if((tileDisplayBlock() == null && lastDisplay == getSelected() && !lastGround)
|
||||
|| (tileDisplayBlock() != null && lastHover == hoverTile && lastDisplay == tileDisplayBlock() && lastGround))
|
||||
return;
|
||||
|
||||
topTable.clear();
|
||||
topTable.top().left().margin(5);
|
||||
|
||||
lastHover = hoverTile;
|
||||
lastDisplay = getSelected();
|
||||
lastGround = tileDisplayBlock() != null;
|
||||
|
||||
if(lastDisplay != null){ //show selected recipe
|
||||
lastGround = false;
|
||||
|
||||
topTable.table(header -> {
|
||||
String keyCombo = "";
|
||||
if(!mobile && Core.settings.getBool("blockselectkeys")){
|
||||
Array<Block> blocks = getByCategory(currentCategory);
|
||||
for(int i = 0; i < blocks.size; i++){
|
||||
if(blocks.get(i) == lastDisplay && (i + 1) / 10 - 1 < blockSelect.length){
|
||||
keyCombo = Core.bundle.format("placement.blockselectkeys", Core.keybinds.get(blockSelect[currentCategory.ordinal()]).key.toString())
|
||||
+ (i < 10 ? "" : Core.keybinds.get(blockSelect[(i + 1) / 10 - 1]).key.toString() + ",")
|
||||
+ Core.keybinds.get(blockSelect[i % 10]).key.toString() + "]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final String keyComboFinal = keyCombo;
|
||||
header.left();
|
||||
header.add(new Image(lastDisplay.icon(Cicon.medium))).size(8 * 4);
|
||||
header.labelWrap(() -> !unlocked(lastDisplay) ? Core.bundle.get("block.unknown") : lastDisplay.localizedName + keyComboFinal)
|
||||
.left().width(190f).padLeft(5);
|
||||
header.add().growX();
|
||||
if(unlocked(lastDisplay)){
|
||||
header.addButton("?", Styles.clearPartialt, () -> {
|
||||
ui.content.show(lastDisplay);
|
||||
Events.fire(new BlockInfoEvent());
|
||||
}).size(8 * 5).padTop(-5).padRight(-5).right().grow().name("blockinfo");
|
||||
}
|
||||
}).growX().left();
|
||||
topTable.row();
|
||||
//add requirement table
|
||||
topTable.table(req -> {
|
||||
req.top().left();
|
||||
|
||||
for(ItemStack stack : lastDisplay.requirements){
|
||||
req.table(line -> {
|
||||
line.left();
|
||||
line.addImage(stack.item.icon(Cicon.small)).size(8 * 2);
|
||||
line.add(stack.item.localizedName).maxWidth(140f).fillX().color(Color.lightGray).padLeft(2).left().get().setEllipsis(true);
|
||||
line.labelWrap(() -> {
|
||||
TileEntity core = player.getClosestCore();
|
||||
if(core == null || state.rules.infiniteResources) return "*/*";
|
||||
|
||||
int amount = core.items.get(stack.item);
|
||||
int stackamount = Math.round(stack.amount * state.rules.buildCostMultiplier);
|
||||
String color = (amount < stackamount / 2f ? "[red]" : amount < stackamount ? "[accent]" : "[white]");
|
||||
|
||||
return color + ui.formatAmount(amount) + "[white]/" + stackamount;
|
||||
}).padLeft(5);
|
||||
}).left();
|
||||
req.row();
|
||||
}
|
||||
}).growX().left().margin(3);
|
||||
|
||||
if(state.rules.bannedBlocks.contains(lastDisplay)){
|
||||
topTable.row();
|
||||
topTable.table(b -> {
|
||||
b.addImage(Icon.cancelSmall).padRight(2).color(Color.scarlet);
|
||||
b.add("$banned");
|
||||
b.left();
|
||||
}).padTop(2).left();
|
||||
}
|
||||
|
||||
}else if(tileDisplayBlock() != null){ //show selected tile
|
||||
lastDisplay = tileDisplayBlock();
|
||||
topTable.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(lastDisplay.getDisplayIcon(hoverTile))).size(8 * 4);
|
||||
t.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
if(hoverTile.getTeam() == player.getTeam()){
|
||||
topTable.row();
|
||||
topTable.table(t -> {
|
||||
t.left().defaults().left();
|
||||
lastDisplay.display(hoverTile, t);
|
||||
}).left().growX();
|
||||
}
|
||||
}
|
||||
});
|
||||
}).colspan(3).fillX().visible(() -> getSelected() != null || tileDisplayBlock() != null).touchable(Touchable.enabled);
|
||||
frame.row();
|
||||
frame.addImage().color(Pal.gray).colspan(3).height(4).growX();
|
||||
frame.row();
|
||||
frame.table(Tex.pane2, blocksSelect -> {
|
||||
blocksSelect.margin(4).marginTop(0);
|
||||
blocksSelect.pane(blocks -> blockTable = blocks).height(194f).update(pane -> {
|
||||
if(pane.hasScroll()){
|
||||
Element result = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(result == null || !result.isDescendantOf(pane)){
|
||||
Core.scene.setScrollFocus(null);
|
||||
}
|
||||
}
|
||||
}).grow().get().setStyle(Styles.smallPane);
|
||||
blocksSelect.row();
|
||||
blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
frame.table(categories -> {
|
||||
categories.bottom();
|
||||
categories.add(new Image(Styles.black6){
|
||||
@Override
|
||||
public void draw(){
|
||||
if(height <= Scl.scl(3f)) return;
|
||||
getDrawable().draw(x, y, width, height - Scl.scl(3f));
|
||||
}
|
||||
}).colspan(2).growX().growY().padTop(-3f).row();
|
||||
categories.defaults().size(50f);
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
|
||||
//update category empty values
|
||||
for(Category cat : Category.all){
|
||||
Array<Block> blocks = getByCategory(cat);
|
||||
categoryEmpty[cat.ordinal()] = blocks.isEmpty();
|
||||
}
|
||||
|
||||
int f = 0;
|
||||
for(Category cat : getCategories()){
|
||||
if(f++ % 2 == 0) categories.row();
|
||||
|
||||
if(categoryEmpty[cat.ordinal()]){
|
||||
categories.addImage(Styles.black6);
|
||||
continue;
|
||||
}
|
||||
|
||||
categories.addImageButton(Core.atlas.drawable("icon-" + cat.name() + "-smaller"), Styles.clearToggleTransi, () -> {
|
||||
currentCategory = cat;
|
||||
if(control.input.block != null){
|
||||
control.input.block = getSelectedBlock(currentCategory);
|
||||
}
|
||||
rebuildCategory.run();
|
||||
}).group(group).update(i -> i.setChecked(currentCategory == cat)).name("category-" + cat.name());
|
||||
}
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
|
||||
rebuildCategory.run();
|
||||
frame.update(() -> {
|
||||
if(gridUpdate(control.input)) rebuildCategory.run();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Array<Category> getCategories(){
|
||||
returnCatArray.clear();
|
||||
returnCatArray.addAll(Category.all);
|
||||
returnCatArray.sort((c1, c2) -> Boolean.compare(categoryEmpty[c1.ordinal()], categoryEmpty[c2.ordinal()]));
|
||||
return returnCatArray;
|
||||
}
|
||||
|
||||
Array<Block> getByCategory(Category cat){
|
||||
returnArray.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.category == cat && block.isVisible() && unlocked(block)){
|
||||
returnArray.add(block);
|
||||
}
|
||||
}
|
||||
returnArray.sort((b1, b2) -> {
|
||||
int locked = -Boolean.compare(unlocked(b1), unlocked(b2));
|
||||
if(locked != 0) return locked;
|
||||
return Boolean.compare(state.rules.bannedBlocks.contains(b1), state.rules.bannedBlocks.contains(b2));
|
||||
});
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
Block getSelectedBlock(Category cat){
|
||||
if(selectedBlocks.get(cat) == null){
|
||||
selectedBlocks.put(cat, getByCategory(cat).find(this::unlocked));
|
||||
}
|
||||
return selectedBlocks.get(cat);
|
||||
}
|
||||
|
||||
boolean unlocked(Block block){
|
||||
return !world.isZone() || data.isUnlocked(block);
|
||||
}
|
||||
|
||||
/** Returns the currently displayed block in the top box. */
|
||||
Block getSelected(){
|
||||
Block toDisplay = null;
|
||||
|
||||
Vector2 v = topTable.stageToLocalCoordinates(Core.input.mouse());
|
||||
|
||||
//setup hovering tile
|
||||
if(!Core.scene.hasMouse() && topTable.hit(v.x, v.y, false) == null){
|
||||
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(tile != null){
|
||||
hoverTile = tile.link();
|
||||
}else{
|
||||
hoverTile = null;
|
||||
}
|
||||
}else{
|
||||
hoverTile = null;
|
||||
}
|
||||
|
||||
//block currently selected
|
||||
if(control.input.block != null){
|
||||
toDisplay = control.input.block;
|
||||
}
|
||||
|
||||
//block hovered on in build menu
|
||||
if(hovered != null){
|
||||
toDisplay = hovered;
|
||||
}
|
||||
|
||||
return toDisplay;
|
||||
}
|
||||
|
||||
/** Returns the block currently being hovered over in the world. */
|
||||
Block tileDisplayBlock(){
|
||||
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.drop() != null && hoverTile.block() == Blocks.air ? hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : hoverTile.floor() : null;
|
||||
}
|
||||
}
|
||||
155
core/src/mindustry/ui/fragments/PlayerListFragment.java
Normal file
155
core/src/mindustry/ui/fragments/PlayerListFragment.java
Normal file
@@ -0,0 +1,155 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.scene.*;
|
||||
import arc.scene.event.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.net.*;
|
||||
import mindustry.net.Packets.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class PlayerListFragment extends Fragment{
|
||||
private boolean visible = false;
|
||||
private Table content = new Table().marginRight(13f).marginLeft(13f);
|
||||
private Interval timer = new Interval();
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
parent.fill(cont -> {
|
||||
cont.visible(() -> visible);
|
||||
cont.update(() -> {
|
||||
if(!(net.active() && !state.is(State.menu))){
|
||||
visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(visible && timer.get(20)){
|
||||
rebuild();
|
||||
content.pack();
|
||||
content.act(Core.graphics.getDeltaTime());
|
||||
//TODO hack
|
||||
Core.scene.act(0f);
|
||||
}
|
||||
});
|
||||
|
||||
cont.table(Tex.buttonTrans, pane -> {
|
||||
pane.label(() -> Core.bundle.format(playerGroup.size() == 1 ? "players.single" : "players", playerGroup.size()));
|
||||
pane.row();
|
||||
pane.pane(content).grow().get().setScrollingDisabled(true, false);
|
||||
pane.row();
|
||||
|
||||
pane.table(menu -> {
|
||||
menu.defaults().growX().height(50f).fillY();
|
||||
|
||||
menu.addButton("$server.bans", ui.bans::show).disabled(b -> net.client());
|
||||
menu.addButton("$server.admins", ui.admins::show).disabled(b -> net.client());
|
||||
menu.addButton("$close", this::toggle);
|
||||
}).margin(0f).pad(10f).growX();
|
||||
|
||||
}).touchable(Touchable.enabled).margin(14f);
|
||||
});
|
||||
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public void rebuild(){
|
||||
content.clear();
|
||||
|
||||
float h = 74f;
|
||||
|
||||
playerGroup.all().sort((p1, p2) -> p1.getTeam().compareTo(p2.getTeam()));
|
||||
playerGroup.all().each(user -> {
|
||||
NetConnection connection = user.con;
|
||||
|
||||
if(connection == null && net.server() && !user.isLocal) return;
|
||||
|
||||
Table button = new Table();
|
||||
button.left();
|
||||
button.margin(5).marginBottom(10);
|
||||
|
||||
Table table = new Table(){
|
||||
@Override
|
||||
public void draw(){
|
||||
super.draw();
|
||||
Draw.color(Pal.gray);
|
||||
Draw.alpha(parentAlpha);
|
||||
Lines.stroke(Scl.scl(4f));
|
||||
Lines.rect(x, y, width, height);
|
||||
Draw.reset();
|
||||
}
|
||||
};
|
||||
table.margin(8);
|
||||
table.add(new Image(user.getIconRegion()).setScaling(Scaling.none)).grow();
|
||||
|
||||
button.add(table).size(h);
|
||||
button.labelWrap("[#" + user.color.toString().toUpperCase() + "]" + user.name).width(170f).pad(10);
|
||||
button.add().grow();
|
||||
|
||||
button.addImage(Icon.admin).visible(() -> user.isAdmin && !(!user.isLocal && net.server())).padRight(5).get().updateVisibility();
|
||||
|
||||
if((net.server() || player.isAdmin) && !user.isLocal && (!user.isAdmin || net.server())){
|
||||
button.add().growY();
|
||||
|
||||
float bs = (h) / 2f;
|
||||
|
||||
button.table(t -> {
|
||||
t.defaults().size(bs);
|
||||
|
||||
t.addImageButton(Icon.banSmall, Styles.clearPartiali,
|
||||
() -> ui.showConfirm("$confirm", "$confirmban", () -> Call.onAdminRequest(user, AdminAction.ban)));
|
||||
t.addImageButton(Icon.cancelSmall, Styles.clearPartiali,
|
||||
() -> ui.showConfirm("$confirm", "$confirmkick", () -> Call.onAdminRequest(user, AdminAction.kick)));
|
||||
|
||||
t.row();
|
||||
|
||||
t.addImageButton(Icon.adminSmall, Styles.clearTogglePartiali, () -> {
|
||||
if(net.client()) return;
|
||||
|
||||
String id = user.uuid;
|
||||
|
||||
if(netServer.admins.isAdmin(id, connection.address)){
|
||||
ui.showConfirm("$confirm", "$confirmunadmin", () -> netServer.admins.unAdminPlayer(id));
|
||||
}else{
|
||||
ui.showConfirm("$confirm", "$confirmadmin", () -> netServer.admins.adminPlayer(id, user.usid));
|
||||
}
|
||||
})
|
||||
.update(b -> b.setChecked(user.isAdmin))
|
||||
.disabled(b -> net.client())
|
||||
.touchable(() -> net.client() ? Touchable.disabled : Touchable.enabled)
|
||||
.checked(user.isAdmin);
|
||||
|
||||
t.addImageButton(Icon.zoomSmall, Styles.clearPartiali, () -> Call.onAdminRequest(user, AdminAction.trace));
|
||||
|
||||
}).padRight(12).size(bs + 10f, bs);
|
||||
}else if((!user.isLocal && !user.isAdmin) && net.client() && playerGroup.size() >= 3){ //votekick
|
||||
button.add().growY();
|
||||
|
||||
button.addImageButton(Icon.banSmall, Styles.clearPartiali,
|
||||
() -> ui.showConfirm("$confirm", "$confirmvotekick", () -> Call.sendChatMessage("/votekick " + user.name))).size(h);
|
||||
}
|
||||
|
||||
content.add(button).padBottom(-6).width(350f).maxHeight(h + 14);
|
||||
content.row();
|
||||
content.addImage().height(4f).color(state.rules.pvp ? user.getTeam().color : Pal.gray).growX();
|
||||
content.row();
|
||||
});
|
||||
|
||||
content.marginBottom(5);
|
||||
}
|
||||
|
||||
public void toggle(){
|
||||
visible = !visible;
|
||||
if(visible){
|
||||
rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
221
core/src/mindustry/ui/fragments/ScriptConsoleFragment.java
Normal file
221
core/src/mindustry/ui/fragments/ScriptConsoleFragment.java
Normal file
@@ -0,0 +1,221 @@
|
||||
package mindustry.ui.fragments;
|
||||
|
||||
import arc.*;
|
||||
import arc.Input.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.Label.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static arc.Core.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class ScriptConsoleFragment extends Table{
|
||||
private final static int messagesShown = 30;
|
||||
private Array<String> messages = new Array<>();
|
||||
private boolean open = false, shown;
|
||||
private TextField chatfield;
|
||||
private Label fieldlabel = new Label(">");
|
||||
private BitmapFont font;
|
||||
private GlyphLayout layout = new GlyphLayout();
|
||||
private float offsetx = Scl.scl(4), offsety = Scl.scl(4), fontoffsetx = Scl.scl(2), chatspace = Scl.scl(50);
|
||||
private Color shadowColor = new Color(0, 0, 0, 0.4f);
|
||||
private float textspacing = Scl.scl(10);
|
||||
private Array<String> history = new Array<>();
|
||||
private int historyPos = 0;
|
||||
private int scrollPos = 0;
|
||||
private Fragment container = new Fragment(){
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
scene.add(ScriptConsoleFragment.this);
|
||||
}
|
||||
};
|
||||
|
||||
public ScriptConsoleFragment(){
|
||||
|
||||
setFillParent(true);
|
||||
font = Fonts.def;
|
||||
|
||||
visible(() -> {
|
||||
if(input.keyTap(Binding.console) && !Vars.net.client() && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){
|
||||
shown = !shown;
|
||||
if(shown && !open && enableConsole){
|
||||
toggle();
|
||||
}
|
||||
clearChatInput();
|
||||
}
|
||||
|
||||
return shown && !Vars.net.active();
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
if(input.keyTap(Binding.chat) && enableConsole && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){
|
||||
toggle();
|
||||
}
|
||||
|
||||
if(open){
|
||||
if(input.keyTap(Binding.chat_history_prev) && historyPos < history.size - 1){
|
||||
if(historyPos == 0) history.set(0, chatfield.getText());
|
||||
historyPos++;
|
||||
updateChat();
|
||||
}
|
||||
if(input.keyTap(Binding.chat_history_next) && historyPos > 0){
|
||||
historyPos--;
|
||||
updateChat();
|
||||
}
|
||||
}
|
||||
|
||||
scrollPos = (int)Mathf.clamp(scrollPos + input.axis(Binding.chat_scroll), 0, Math.max(0, messages.size - messagesShown));
|
||||
});
|
||||
|
||||
history.insert(0, "");
|
||||
setup();
|
||||
}
|
||||
|
||||
public Fragment container(){
|
||||
return container;
|
||||
}
|
||||
|
||||
public void clearMessages(){
|
||||
messages.clear();
|
||||
history.clear();
|
||||
history.insert(0, "");
|
||||
}
|
||||
|
||||
private void setup(){
|
||||
fieldlabel.setStyle(new LabelStyle(fieldlabel.getStyle()));
|
||||
fieldlabel.getStyle().font = font;
|
||||
fieldlabel.setStyle(fieldlabel.getStyle());
|
||||
|
||||
chatfield = new TextField("", new TextField.TextFieldStyle(scene.getStyle(TextField.TextFieldStyle.class)));
|
||||
chatfield.setMaxLength(Vars.maxTextLength);
|
||||
chatfield.getStyle().background = null;
|
||||
chatfield.getStyle().font = Fonts.chat;
|
||||
chatfield.getStyle().fontColor = Color.white;
|
||||
chatfield.setStyle(chatfield.getStyle());
|
||||
|
||||
bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(6f);
|
||||
|
||||
add(chatfield).padBottom(offsety).padLeft(offsetx).growX().padRight(offsetx).height(28);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float opacity = 1f;
|
||||
float textWidth = graphics.getWidth() - offsetx*2f;
|
||||
|
||||
Draw.color(shadowColor);
|
||||
|
||||
if(open){
|
||||
Fill.crect(offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight() - 1);
|
||||
}
|
||||
|
||||
super.draw();
|
||||
|
||||
float spacing = chatspace;
|
||||
|
||||
chatfield.visible(open);
|
||||
fieldlabel.visible(open);
|
||||
|
||||
Draw.color(shadowColor);
|
||||
Draw.alpha(shadowColor.a * opacity);
|
||||
|
||||
float theight = offsety + spacing + getMarginBottom();
|
||||
for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos; i++){
|
||||
|
||||
layout.setText(font, messages.get(i), Color.white, textWidth, Align.bottomLeft, true);
|
||||
theight += layout.height + textspacing;
|
||||
if(i - scrollPos == 0) theight -= textspacing + 1;
|
||||
|
||||
font.getCache().clear();
|
||||
font.getCache().addText(messages.get(i), fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true);
|
||||
|
||||
if(!open){
|
||||
font.getCache().setAlphas(opacity);
|
||||
Draw.color(0, 0, 0, shadowColor.a * opacity);
|
||||
}else{
|
||||
font.getCache().setAlphas(opacity);
|
||||
}
|
||||
|
||||
Fill.crect(offsetx, theight - layout.height - 2, textWidth + Scl.scl(4f), layout.height + textspacing);
|
||||
Draw.color(shadowColor);
|
||||
Draw.alpha(opacity * shadowColor.a);
|
||||
|
||||
font.getCache().draw();
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
private void sendMessage(){
|
||||
String message = chatfield.getText();
|
||||
clearChatInput();
|
||||
|
||||
if(message.replaceAll(" ", "").isEmpty()) return;
|
||||
|
||||
history.insert(1, message);
|
||||
|
||||
addMessage("[lightgray]> " + message.replace("[", "[["));
|
||||
addMessage(mods.getScripts().runConsole(message).replace("[", "[["));
|
||||
}
|
||||
|
||||
public void toggle(){
|
||||
|
||||
if(!open){
|
||||
scene.setKeyboardFocus(chatfield);
|
||||
open = !open;
|
||||
if(mobile){
|
||||
TextInput input = new TextInput();
|
||||
input.maxLength = maxTextLength;
|
||||
input.accepted = text -> {
|
||||
chatfield.setText(text);
|
||||
sendMessage();
|
||||
hide();
|
||||
Core.input.setOnscreenKeyboardVisible(false);
|
||||
};
|
||||
input.canceled = this::hide;
|
||||
Core.input.getTextInput(input);
|
||||
}else{
|
||||
chatfield.fireClick();
|
||||
}
|
||||
}else{
|
||||
scene.setKeyboardFocus(null);
|
||||
open = !open;
|
||||
scrollPos = 0;
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
scene.setKeyboardFocus(null);
|
||||
open = false;
|
||||
clearChatInput();
|
||||
}
|
||||
|
||||
public void updateChat(){
|
||||
chatfield.setText(history.get(historyPos));
|
||||
chatfield.setCursorPosition(chatfield.getText().length());
|
||||
}
|
||||
|
||||
public void clearChatInput(){
|
||||
historyPos = 0;
|
||||
history.set(0, "");
|
||||
chatfield.setText("");
|
||||
}
|
||||
|
||||
public boolean open(){
|
||||
return open;
|
||||
}
|
||||
|
||||
public void addMessage(String message){
|
||||
messages.insert(0, message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user