diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 99a843e..b935469 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -17,22 +17,24 @@ shar-stat.waveStatus = [lightgray]Status:[] shar-stat.waveItem = [lightgray]Item:[] #Settings -setting.barstyle.name = Unit Information UI: Change Bar Style +setting.barstyle.name = Unit UI: Change Bar Style setting.barstyle.description = Changes the bar sprite in the unit information interface. setting.infoUiScale.name = Information UI Scale -setting.infoUiScale.description = Sets the scale of the information interface. +setting.infoUiScale.description = Sets the scale of the UnitInfo information interface. setting.coreItemCheckRate.name = Resource UI: Update Rate setting.coreItemCheckRate.description = Sets how often the core resources are checked.\nThe slower rate, the better gameplay performance gets. -setting.wavemax.name = Wave Interface: Wave Amount To Display +setting.wavemax.name = Wave UI: Wave Amount To Display setting.wavemax.description = Sets the limit of visible waves in the wave list. setting.infoui.name = Display Information UI setting.infoui.description = Enables the information interface on the left to display.\nWhen disabled, all associated updates will be stopped. setting.waveui.name = Display Wave UI setting.waveui.description = Enables the top-left wave interface to display.\nWhen disabled, all associated updates will be stopped. -setting.pastwave.name = Wave Interface: Display Previous Wave +setting.pastwave.name = Wave UI: Display Previous Wave setting.pastwave.description = Displays the previous wave in the wave list.\nThe current wave is highlighted with red color. -setting.emptywave.name = Wave Interface: Display Empty Wave +setting.emptywave.name = Wave UI: Display Empty Wave setting.emptywave.description = Displays empty waves in the wave list. +setting.itemcal.name = Resource UI: Calculate item inc/dec speed. +setting.itemcal.description = Calculate increase/decrease speed of core item and display results. setting.rangeRadius.name = Near Range Margin setting.rangeRadius.description = Sets the range detection distance. @@ -40,9 +42,10 @@ setting.rangeNearby.name = Display Near Range setting.rangeNearby.description = Enables automatic range display.\nIf you approach the range by a certain distance, the range is displayed in advance. setting.allTargetRange.name = Display All Target Ranges setting.allTargetRange.description = Displays all target ranges.\nThe range of targets that cannot be aimed at themselves is shown as gray. -setting.coreRange.name = Display Core Range -setting.coreRange.description = Displays enemy core build-limit range. -setting.RangeShader.name = Enable Range Animation +setting.aliceRange.name = Display Alice Range +setting.aliceRange.description = Displays alice turret range too. +setting.RangeShader.name = Enable Animation +setting.RangeShader.description = Activate easy-to-see animations in return for large frame drops. setting.selectopacity.name = Select Arrow Opacity setting.selectopacity.description = Sets the opacity of selection arrow. diff --git a/assets/bundles/bundle_ko.properties b/assets/bundles/bundle_ko.properties index 5890cdd..fdbef06 100644 --- a/assets/bundles/bundle_ko.properties +++ b/assets/bundles/bundle_ko.properties @@ -30,6 +30,8 @@ setting.pastwave.name = 이전 단계 표시 setting.pastwave.description = 단계 탭에서 이전 단계를 표시합니다. 현재 단계는 빨간색으로 강조됩니다. setting.emptywave.name = 빈 단계 표시 setting.emptywave.description = 단계 탭에서 빈 단계를 표시합니다. +setting.itemcal.name = 자원 탭: 입출력 속도 계산 +setting.itemcal.description = 아이템의 증가/감소 속도를 계산하여 표시합니다. setting.rangeRadius.name = 사거리 접근 거리 setting.rangeRadius.description = 사거리 감지 거리를 설정합니다. @@ -37,9 +39,10 @@ setting.rangeNearby.name = 자동 사거리 표시 setting.rangeNearby.description = 자동 사거리 표시 기능을 활성화합니다. 적 사거리에 일정 거리만큼 접근하면 사거리를 미리 표시합니다. setting.allTargetRange.name = 모든 목표물 사거리 표시 setting.allTargetRange.description = 모든 사거리를 표시합니다. 자신을 조준할 수 없는 대상의 사거리는 회색으로 보여집니다. -setting.coreRange.name = 코어 사거리 표시 -setting.coreRange.description = 적 코어의 건설 제한 범위를 표시합니다. -setting.RangeShader.name = 사거리 에니매이션 활성화 +setting.aliceRange.name = 아군 사거리 표시 +setting.aliceRange.description = 아군 사거리도 표시합니다. +setting.RangeShader.name = 에니매이션 활성화 +setting.RangeShader.description = 큰 프레임 드랍을 대가로 보기 편한 에니메이션을 활성화합니다. setting.selectopacity.name = 선택 화살표 투명도 setting.selectopacity.description = 선택 화살표의 투명도를 조절합니다. diff --git a/assets/mod.json b/assets/mod.json index 03007e7..d22f894 100644 --- a/assets/mod.json +++ b/assets/mod.json @@ -3,9 +3,9 @@ "displayName": "Unit Information", "author": "Sharlotte", "description": "The mod displays more information in-game, such as unit/building, wave, core, tile, item/unit total info etc", - "version": "1.5.1", + "version": "1.5.2", "main": "UnitInfo.core.Main", - "minGameVersion": "133", + "minGameVersion": "134", "dependencies": [], "hidden": true, "java": true diff --git a/src/UnitInfo/SVars.java b/src/UnitInfo/SVars.java index 1516631..bc57f30 100644 --- a/src/UnitInfo/SVars.java +++ b/src/UnitInfo/SVars.java @@ -16,5 +16,5 @@ public class SVars { public static TextureRegion error = atlas.find("error"); public static RangeShader turretRange; public static LineShader lineShader; - public static boolean jsonGen = true; + public static boolean jsonGen = false; } diff --git a/src/UnitInfo/core/BarInfo.java b/src/UnitInfo/core/BarInfo.java index 1d17719..abdbb44 100644 --- a/src/UnitInfo/core/BarInfo.java +++ b/src/UnitInfo/core/BarInfo.java @@ -30,9 +30,9 @@ import static arc.Core.*; import static mindustry.Vars.*; public class BarInfo { - static Seq strings = Seq.with("","","","","",""); - static FloatSeq numbers = FloatSeq.with(0f,0f,0f,0f,0f,0f); - static Seq colors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); + public static Seq strings = Seq.with("","","","","",""); + public static FloatSeq numbers = FloatSeq.with(0f,0f,0f,0f,0f,0f); + public static Seq colors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); public static void getInfo(T target) throws IllegalAccessException, NoSuchFieldException { for(int i = 0; i < 6; i++) { //init diff --git a/src/UnitInfo/core/HudUi.java b/src/UnitInfo/core/HudUi.java index fa06b58..29d9764 100644 --- a/src/UnitInfo/core/HudUi.java +++ b/src/UnitInfo/core/HudUi.java @@ -1,91 +1,53 @@ package UnitInfo.core; -import UnitInfo.SUtils; import UnitInfo.ui.*; + import arc.*; -import arc.func.Cons; -import arc.func.Floatf; import arc.graphics.*; import arc.graphics.g2d.*; import arc.input.*; import arc.math.*; import arc.math.geom.*; -import arc.scene.*; -import arc.scene.event.*; import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; -import arc.scene.utils.*; import arc.struct.*; import arc.util.*; + import mindustry.*; -import mindustry.content.*; -import mindustry.core.*; -import mindustry.ctype.ContentType; -import mindustry.ctype.UnlockableContent; import mindustry.entities.Units; -import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.logic.Ranged; -import mindustry.type.*; import mindustry.ui.*; -import mindustry.ui.dialogs.BaseDialog; -import mindustry.ui.dialogs.SchematicsDialog; import mindustry.world.*; import mindustry.world.blocks.*; -import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.turrets.*; -import mindustry.world.blocks.distribution.*; -import mindustry.world.blocks.payloads.*; -import mindustry.world.blocks.power.*; -import mindustry.world.blocks.production.*; import mindustry.world.blocks.storage.*; -import mindustry.world.blocks.units.*; import static UnitInfo.SVars.*; import static arc.Core.*; import static mindustry.Vars.*; -import static mindustry.gen.Tex.scrollKnobVerticalThin; public class HudUi { - Seq bars = new Seq<>(); - Table mainTable = new Table(); - Table baseTable = new Table(); - Table unitTable = new Table(); - Table waveTable = new Table(); - Table itemTable = new Table(); - Table waveInfoTable = new Table(); - Table schemListTable = new Table(); - float waveScrollPos, itemScrollPos, weaponScrollPos, schemScrollPos, tagScrollPos; + public Table mainTable = new Table(); + public Table baseTable = new Table(); + public Table waveInfoTable = new Table(); + public UnitDisplay unitTable; + public WaveDisplay waveTable; + public CoreDisplay itemTable; - Teamc shotTarget; - Teamc lockedTarget; - ImageButton lockButton; - boolean locked = false; + public Teamc shotTarget; + public Teamc lockedTarget; + public boolean locked = false; - boolean waveShown, schemShown; - private Schematic firstSchematic; - private final Seq selectedTags = new Seq<>(); - private Runnable rebuildList = () -> {}; + public boolean waveShown; - float a; - int uiIndex = 3; - - //to update tables - int waveamount; - int enemyamount; - - //is this rly good idea? - Seq strings = Seq.with("","","","","",""); - FloatSeq numbers = FloatSeq.with(0f,0f,0f,0f,0f,0f); - Seq colors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); - Seq lastColors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); - CoresItemsDisplay coreItems = new CoresItemsDisplay(Team.baseTeams); - - public final Rect scissor = new Rect(); + public float a; + public int uiIndex = 3; + CoresItemsDisplay coreItems = new CoresItemsDisplay(); @SuppressWarnings("unchecked") public T getTarget(){ @@ -97,7 +59,6 @@ public class HudUi { else return (T) lockedTarget; //if there is locked target, return it first. } - Seq units = Groups.unit.intersect(input.mouseWorldX(), input.mouseWorldY(), 4, 4); // well, 0.5tile is enough to search them if(units.size > 0) return (T) units.peek(); //if there is unit, return it. @@ -113,7 +74,11 @@ public class HudUi { } public void setEvents() { + Events.on(EventType.WaveEvent.class, e -> waveTable.rebuild()); + Events.on(EventType.WorldLoadEvent.class, e -> itemTable.rebuild()); Events.run(EventType.Trigger.update, ()->{ + unitTable.setEvent(); + itemTable.setEvent(); OverDrawer.target = getTarget(); OverDrawer.locked = locked; if(settings.getBool("deadTarget") && locked && lockedTarget != null && !Groups.all.contains(e -> e == lockedTarget)) { @@ -128,10 +93,6 @@ public class HudUi { coreItems.rebuild(); } - if((input.keyDown(KeyCode.shiftRight) || input.keyDown(KeyCode.shiftLeft))){ - if(input.keyTap(KeyCode.r) && lockButton != null) lockButton.change(); - } - if(settings.getBool("autoShooting")) { Unit unit = player.unit(); if (unit.type == null) return; @@ -194,7 +155,7 @@ public class HudUi { table.table(t -> { t.center(); int[] i = {0}; - enemyamount = Groups.unit.count(u -> state.rules.pvp ? (u.team != player.team()) : (u.team == state.rules.waveTeam)); + content.units().each(type -> Groups.unit.contains(u -> u.type == type && (state.rules.pvp ? (u.team != player.team()) : (u.team == state.rules.waveTeam)) && u.isBoss()), type -> { t.table(tt -> tt.stack( @@ -252,468 +213,12 @@ public class HudUi { ); } - void showInfo(Schematic schematic){ - try { - ((SchematicsDialog.SchematicInfoDialog)SUtils.invoke(ui.schematics, "info")).show(schematic); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - } - - void checkTags(Schematic s){ - boolean any = false; - Seq seq = null; - try { - seq = (Seq) SUtils.invoke(ui.schematics, "tags"); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - if(seq == null) return; - for(var tag : s.labels){ - if(!seq.contains(tag)){ - seq.add(tag); - any = true; - } - } - if(any) setSchemTable(); - } - - void showImport(){ - BaseDialog dialog = new BaseDialog("@editor.export"); - dialog.cont.pane(p -> { - p.margin(10f); - p.table(Tex.button, t -> { - TextButton.TextButtonStyle style = Styles.cleart; - t.defaults().size(280f, 60f).left(); - t.row(); - t.button("@schematic.copy.import", Icon.copy, style, () -> { - dialog.hide(); - try{ - Schematic s = Schematics.readBase64(Core.app.getClipboardText()); - s.removeSteamID(); - schematics.add(s); - setSchemTable(); - ui.showInfoFade("@schematic.saved"); - checkTags(s); - showInfo(s); - }catch(Throwable e){ - ui.showException(e); - } - }).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart)); - t.row(); - t.button("@schematic.importfile", Icon.download, style, () -> platform.showFileChooser(true, schematicExtension, file -> { - dialog.hide(); - - try{ - Schematic s = Schematics.read(file); - s.removeSteamID(); - schematics.add(s); - setSchemTable(); - showInfo(s); - checkTags(s); - }catch(Exception e){ - ui.showException(e); - } - })).marginLeft(12f); - t.row(); - if(steam){ - t.button("@schematic.browseworkshop", Icon.book, style, () -> { - dialog.hide(); - platform.openWorkshop(); - }).marginLeft(12f); - } - }); - }); - - dialog.addCloseButton(); - dialog.show(); - } - - void showExport(Schematic s){ - BaseDialog dialog = new BaseDialog("@editor.export"); - dialog.cont.pane(p -> { - p.margin(10f); - p.table(Tex.button, t -> { - TextButton.TextButtonStyle style = Styles.cleart; - t.defaults().size(280f, 60f).left(); - if(steam && !s.hasSteamID()){ - t.button("@schematic.shareworkshop", Icon.book, style, - () -> platform.publish(s)).marginLeft(12f); - t.row(); - dialog.hide(); - } - t.button("@schematic.copy", Icon.copy, style, () -> { - dialog.hide(); - ui.showInfoFade("@copied"); - Core.app.setClipboardText(schematics.writeBase64(s)); - }).marginLeft(12f); - t.row(); - t.button("@schematic.exportfile", Icon.export, style, () -> { - dialog.hide(); - platform.export(s.name(), schematicExtension, file -> Schematics.write(s, file)); - }).marginLeft(12f); - }); - }); - - dialog.addCloseButton(); - dialog.show(); - } - - void tagsChanged(){ - rebuildList.run(); - Seq tags = null; - try { - tags = (Seq) SUtils.invoke(ui.schematics, "tags"); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - if(tags == null) return; - Core.settings.putJson("schematic-tags", String.class, tags); - } - - void addTag(Schematic s, String tag){ - s.labels.add(tag); - s.save(); - tagsChanged(); - } - - void removeTag(Schematic s, String tag){ - s.labels.remove(tag); - s.save(); - tagsChanged(); - } - - //shows a dialog for creating a new tag - void showNewTag(Cons result){ - Seq tags = null; - try { - tags = (Seq) SUtils.invoke(ui.schematics, "tags"); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - if(tags == null) return; - Seq finalTags = tags; - ui.showTextInput("@schematic.addtag", "", "", out -> { - if(finalTags.contains(out)){ - ui.showInfo("@schematic.tagexists"); - }else{ - finalTags.add(out); - tagsChanged(); - result.get(out); - } - }); - } - - void showNewIconTag(Cons cons){ - Seq tags = null; - try { - tags = (Seq) SUtils.invoke(ui.schematics, "tags"); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - if(tags == null) return; - Seq finalTags = tags; - new Dialog(){{ - closeOnBack(); - setFillParent(true); - - cont.pane(t -> - resized(true, () -> { - t.clearChildren(); - t.marginRight(19f); - t.defaults().size(48f); - - int cols = (int)Math.min(20, Core.graphics.getWidth() / Scl.scl(52f)); - - for(ContentType ctype : defaultContentIcons){ - t.row(); - t.image().colspan(cols).growX().width(Float.NEGATIVE_INFINITY).height(3f).color(Pal.accent); - t.row(); - - int i = 0; - for(UnlockableContent u : content.getBy(ctype).as()){ - if(!u.isHidden() && u.unlockedNow() && u.hasEmoji() && !finalTags.contains(u.emoji())){ - t.button(new TextureRegionDrawable(u.uiIcon), Styles.cleari, iconMed, () -> { - String out = u.emoji() + ""; - - finalTags.add(out); - tagsChanged(); - cons.get(out); - - hide(); - }); - - if(++i % cols == 0) t.row(); - } - } - } - }) - ); - buttons.button("@back", Icon.left, this::hide).size(210f, 64f); - }}.show(); - } - - void buildTags(Schematic schem, Table t, boolean name){ - t.clearChildren(); - t.left(); - Seq tags = null; - try { - tags = (Seq) SUtils.invoke(ui.schematics, "tags"); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - if(tags == null) return; - - //sort by order in the main target array. the complexity of this is probably awful - Seq finalTags = tags; - schem.labels.sort((Floatf) finalTags::indexOf); - - if(name) t.add("@schematic.tags").padRight(4); - t.pane(s -> { - s.left(); - s.defaults().pad(3).height(42f); - for(var tag : schem.labels){ - s.table(Tex.button, i -> { - i.add(tag).padRight(4).height(42f).labelAlign(Align.center); - i.button(Icon.cancelSmall, Styles.emptyi, () -> { - removeTag(schem, tag); - buildTags(schem, t, name); - }).size(42f).padRight(-9f).padLeft(-9f); - }); - } - - }).fillX().left().height(42f).scrollY(false); - - Seq finalTags1 = tags; - t.button(Icon.addSmall, () -> { - var dialog = new BaseDialog("@schematic.addtag"); - dialog.addCloseButton(); - dialog.cont.pane(p -> { - p.clearChildren(); - - float sum = 0f; - Table current = new Table().left(); - for(var tag : finalTags1){ - if(schem.labels.contains(tag)) continue; - - var next = Elem.newButton(tag, () -> { - addTag(schem, tag); - buildTags(schem, t, name); - dialog.hide(); - }); - next.getLabel().setWrap(false); - - next.pack(); - float w = next.getPrefWidth() + Scl.scl(6f); - - if(w + sum >= Core.graphics.getWidth() * (Core.graphics.isPortrait() ? 1f : 0.8f)){ - p.add(current).row(); - current = new Table(); - current.left(); - current.add(next).height(42f).pad(2); - sum = 0; - }else{ - current.add(next).height(42f).pad(2); - } - - sum += w; - } - - if(sum > 0){ - p.add(current).row(); - } - - Cons handleTag = res -> { - dialog.hide(); - addTag(schem, res); - buildTags(schem, t, name); - }; - - p.row(); - - p.table(v -> { - v.left().defaults().fillX().height(42f).pad(2); - v.button("@schematic.texttag", Icon.add, () -> showNewTag(handleTag)).wrapLabel(false).get().getLabelCell().padLeft(4); - v.button("@schematic.icontag", Icon.add, () -> showNewIconTag(handleTag)).wrapLabel(false).get().getLabelCell().padLeft(4); - }); - }); - dialog.show(); - }).size(42f).tooltip("@schematic.addtag"); - } - - void setSchemTable() { - schemListTable.clear(); - Table table = schemListTable; - table.right(); - table.button("Schematic List", Icon.downOpen, Styles.squareTogglet, () -> schemShown = !schemShown).width(160f).height(60f).checked(b -> { - Image image = (Image)b.getCells().first().get(); - image.setDrawable(schemShown ? Icon.upOpen : Icon.downOpen); - return schemShown; - }).row(); - table.collapser(t -> { - t.background(Styles.black8).defaults().maxHeight(72 * 8f).maxWidth(160f); - rebuildList = () -> { - t.clearChildren(); - ScrollPane pane1 = t.pane(Styles.nonePane, p -> { - p.left().defaults().pad(2).height(42f); - try { - for(String tag : (Seq)SUtils.invoke(ui.schematics, "tags")){ - p.button(tag, Styles.togglet, () -> { - if(selectedTags.contains(tag)){ - selectedTags.remove(tag); - }else{ - selectedTags.add(tag); - } - rebuildList.run(); - }).checked(selectedTags.contains(tag)).with(c -> c.getLabel().setWrap(false)); - } - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - }).fillX().height(42f).get(); - pane1.update(() -> { - Element result = scene.hit(input.mouseX(), input.mouseY(), true); - if(pane1.hasScroll() && (result == null || !result.isDescendantOf(pane1))) - scene.setScrollFocus(null); - tagScrollPos = pane1.getScrollX(); - }); - - pane1.setOverscroll(false, false); - pane1.setScrollingDisabled(false, true); - pane1.setScrollXForce(tagScrollPos); - - t.row(); - - ScrollPane pane = t.pane(Styles.nonePane, p -> { - p.table(tt -> { - firstSchematic = null; - - tt.button("Import", Icon.download, this::showImport).width(160f).height(64f).row(); - for(Schematic s : schematics.all()){ - if(selectedTags.any() && !s.labels.containsAll(selectedTags)) continue; - if(firstSchematic == null) firstSchematic = s; - - Button[] sel = {null}; - sel[0] = tt.button(b -> { - b.top(); - b.margin(0f); - b.table(buttons -> { - buttons.left(); - buttons.defaults().size(162/4f); - - ImageButton.ImageButtonStyle style = Styles.clearPartiali; - - buttons.button(Icon.info, style, () -> { - showInfo(s); - }); - - buttons.button(Icon.upload, style, () -> { - showExport(s); - }); - - buttons.button(Icon.pencil, style, () -> { - new Dialog("@schematic.rename"){{ - setFillParent(true); - - cont.margin(30); - - cont.add("@schematic.tags").padRight(6f); - cont.table(tags -> buildTags(s, tags, false)).maxWidth(400f).fillX().left().row(); - - cont.margin(30).add("@name").padRight(6f); - TextField nameField = cont.field(s.name(), null).size(400f, 55f).left().get(); - - cont.row(); - - cont.margin(30).add("@editor.description").padRight(6f); - TextField descField = cont.area(s.description(), Styles.areaField, t -> {}).size(400f, 140f).left().get(); - - Runnable accept = () -> { - s.tags.put("name", nameField.getText()); - s.tags.put("description", descField.getText()); - s.save(); - hide(); - setSchemTable(); - }; - - buttons.defaults().size(120, 54).pad(4); - buttons.button("@ok", accept).disabled(b -> nameField.getText().isEmpty()); - buttons.button("@cancel", this::hide); - - keyDown(KeyCode.enter, () -> { - if(!nameField.getText().isEmpty() && Core.scene.getKeyboardFocus() != descField){ - accept.run(); - } - }); - keyDown(KeyCode.escape, this::hide); - keyDown(KeyCode.back, this::hide); - show(); - }}; - }); - - if(s.hasSteamID()){ - buttons.button(Icon.link, style, () -> platform.viewListing(s)); - }else{ - buttons.button(Icon.trash, style, () -> { - if(s.mod != null){ - ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.displayName())); - }else{ - ui.showConfirm("@confirm", "@schematic.delete.confirm", () -> { - schematics.remove(s); - setSchemTable(); - }); - } - }); - } - - }).growX().height(50f); - b.row(); - b.stack(new SchematicsDialog.SchematicImage(s).setScaling(Scaling.fit), new Table(n -> { - n.top(); - n.table(Styles.black3, c -> { - Label label = c.add(s.name()).style(Styles.outlineLabel).color(Color.white).top().growX().maxWidth(200f - 8f).get(); - label.setEllipsis(true); - label.setAlignment(Align.center); - }).growX().margin(1).pad(4).maxWidth(Scl.scl(160f - 8f)).padBottom(0); - })).size(160f); - }, () -> { - if(sel[0].childrenPressed()) return; - control.input.useSchematic(s); - - }).pad(4).style(Styles.cleari).get(); - - sel[0].getStyle().up = Tex.pane; - tt.row(); - } - - if(firstSchematic == null){ - tt.add("@none"); - } - }); - }).grow().get(); - - pane.update(() -> { - Element result = scene.hit(input.mouseX(), input.mouseY(), true); - if(pane.hasScroll() && (result == null || !result.isDescendantOf(pane))) - scene.setScrollFocus(null); - schemScrollPos = pane.getScrollY(); - }); - - pane.setOverscroll(false, false); - pane.setScrollingDisabled(true, false); - pane.setScrollYForce(schemScrollPos); - }; - rebuildList.run(); - }, true, () -> schemShown); - } - public void addSchemTable() { if(mobile) return; - setSchemTable(); Table table = (Table) scene.find("minimap/position"); table.row(); - table.add(schemListTable); + table.add(new SchemDisplay()); } public void addWaveInfoTable() { @@ -773,12 +278,11 @@ public class HudUi { uiIndex = index; buttons.each(b -> b.setChecked(buttons.indexOf(b) == index)); label.setText(bundle.get(hud)); - addBars(); - addUnitTable(); - addWaveTable(); - addItemTable(); table.removeChild(baseTable); labelTable.setPosition(buttons.items[uiIndex].x, buttons.items[uiIndex].y); + unitTable = new UnitDisplay(); + waveTable = new WaveDisplay(); + itemTable = new CoreDisplay(); baseTable = table.table(tt -> tt.stack(unitTable, waveTable, itemTable, labelTable).align(Align.left).left().visible(() -> settings.getBool("infoui"))).left().get(); a = 1f; } @@ -812,6 +316,9 @@ public class HudUi { t.row(); } }); + unitTable = new UnitDisplay(); + waveTable = new WaveDisplay(); + itemTable = new CoreDisplay(); baseTable = table.table(tt -> tt.stack(unitTable, waveTable, itemTable, labelTable).align(Align.left).left().visible(() -> settings.getBool("infoui"))).left().get(); table.fillParent = true; @@ -819,635 +326,4 @@ public class HudUi { }); ui.hudGroup.addChild(mainTable); } - - public TextureRegion getRegions(int i){ - Teamc target = getTarget(); - TextureRegion region = clear; - - if(i == 0){ - if(target instanceof Healthc) region = SIcons.health; - } else if(i == 1){ - if(target instanceof Turret.TurretBuild || - target instanceof MassDriver.MassDriverBuild){ - region = SIcons.reload; - } else if((target instanceof Unit unit && unit.type != null) || - target instanceof ForceProjector.ForceBuild){ - region = SIcons.shield; - } else if(target instanceof MendProjector.MendBuild || - target instanceof OverdriveProjector.OverdriveBuild || - target instanceof ConstructBlock.ConstructBuild || - target instanceof UnitFactory.UnitFactoryBuild || - target instanceof Reconstructor.ReconstructorBuild || - target instanceof Drill.DrillBuild || - target instanceof GenericCrafter.GenericCrafterBuild){ - //region = SIcons.progress; - } else if(target instanceof PowerNode.PowerNodeBuild || - target instanceof PowerGenerator.GeneratorBuild){ - region = SIcons.power; - } - } else if(i == 2){ - if(target instanceof ItemTurret.ItemTurretBuild){ - region = SIcons.ammo; - } else if(target instanceof LiquidTurret.LiquidTurretBuild){ - region = SIcons.liquid; - } else if(target instanceof PowerTurret.PowerTurretBuild || - target instanceof PowerNode.PowerNodeBuild){ - region = SIcons.power; - } else if((target instanceof Building b && b.block.hasItems) || - (target instanceof Unit unit && unit.type != null)){ - region = SIcons.item; - } - } else if(i == 3){ - if(target instanceof Unit unit && unit.type != null || - target instanceof UnitFactory.UnitFactoryBuild || - target instanceof Reconstructor.ReconstructorBuild){ - //region = SIcons.unit; - } else if(target instanceof AttributeCrafter.AttributeCrafterBuild || - target instanceof SolidPump.SolidPumpBuild || - target instanceof ThermalGenerator.ThermalGeneratorBuild){ - //region = SIcons.attr; - } else if(target instanceof PowerNode.PowerNodeBuild){ - region = SIcons.power; - } else if(target instanceof OverdriveProjector.OverdriveBuild){ - //region = SIcons.boost; - } - } else if(i == 4){ - if(target instanceof Unit unit && target instanceof Payloadc && unit.type != null){ - - } else if(target instanceof PowerNode.PowerNodeBuild){ - region = SIcons.power; - } else if(target instanceof Building b && b.block.hasLiquids){ - region = SIcons.liquid; - } - } else if(i == 5){ - if(target instanceof Unit unit && state.rules.unitAmmo && unit.type != null){ - region = SIcons.ammo; - }else if(target instanceof PowerNode.PowerNodeBuild || - (target instanceof Building b && b.block.consumes.hasPower())){ - region = SIcons.power; - } - } - - return region; - } - - public Element addBar(int i){ - return new Stack(){{ - add(new Table(t -> { - t.add(new SBar( - () -> BarInfo.strings.get(i), - () -> { - if (BarInfo.colors.get(i) != Color.clear) lastColors.set(i, BarInfo.colors.get(i)); - return lastColors.get(i); - }, - () -> BarInfo.numbers.get(i) - )).width(Scl.scl(modUiScale) * 24 * 8f).height(Scl.scl(modUiScale) * 4 * 8f).growX().left(); - })); - add(new Table(t -> { - t.right(); - t.add(new Image(){ - @Override - public void draw() { - validate(); - - float x = this.x; - float y = this.y; - float scaleX = this.scaleX; - float scaleY = this.scaleY; - Draw.color(Color.white); - Draw.alpha(parentAlpha * color.a); - - TextureRegionDrawable region = new TextureRegionDrawable(getRegions(i)); - float rotation = getRotation(); - if(scaleX != 1 || scaleY != 1 || rotation != 0){ - region.draw(x + imageX, y + imageY, originX - imageX, originY - imageY, - imageWidth, imageHeight, scaleX, scaleY, rotation); - return; - } - region.draw(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); - - Draw.color(colors.get(i)); - if(ScissorStack.push(scissor.set(x, y, imageWidth * scaleX, imageHeight * scaleY * numbers.get(i)))){ - region.draw(x, y, imageWidth * scaleX, imageHeight * scaleY); - ScissorStack.pop(); - } - Draw.reset(); - } - }).size(iconMed * Scl.scl(modUiScale) * 0.75f); - })); - }}; - } - - public void addBars(){ - bars.clear(); - for(int i = 0; i < 6; i++) bars.add(addBar(i)); - } - - public void addWeaponTable(Table table){ - table.table().update(tt -> { - tt.clear(); - if(getTarget() instanceof Unit u && u.type != null && u.hasWeapons()) { - for(int r = 0; r < u.type.weapons.size; r++){ - Weapon weapon = u.type.weapons.get(r); - WeaponMount mount = u.mounts[r]; - int finalR = r; - tt.table(ttt -> { - ttt.left(); - if((1 + finalR) % 4 == 0) ttt.row(); - ttt.stack( - new Table(o -> { - o.left(); - o.add(new Image(!weapon.name.equals("") && weapon.outlineRegion.found() ? weapon.outlineRegion : u.type.uiIcon){ - @Override - public void draw(){ - validate(); - float x = this.x; - float y = this.y; - float scaleX = this.scaleX; - float scaleY = this.scaleY; - Draw.color(color); - Draw.alpha(parentAlpha * color.a); - - if(getDrawable() instanceof TransformDrawable){ - float rotation = getRotation(); - if(scaleX != 1 || scaleY != 1 || rotation != 0){ - getDrawable().draw(x + imageX, y + imageY, originX - imageX, originY - imageY, imageWidth, imageHeight, scaleX, scaleY, rotation); - return; - } - } - y -= (mount.reload) / weapon.reload * weapon.recoil; - if(getDrawable() != null) - getDrawable().draw(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); - } - }).size(Scl.scl(modUiScale) * iconLarge); - }), - new Table(h -> { - h.defaults().growX().height(Scl.scl(modUiScale) * 9f).width(Scl.scl(modUiScale) * iconLarge).padTop(Scl.scl(modUiScale) * 18f); - h.add(new SBar( - () -> "", - () -> Pal.accent.cpy().lerp(Color.orange, mount.reload / weapon.reload), - () -> mount.reload / weapon.reload).rect().init()); - h.pack(); - }) - ); - }).pad(4); - } - } - }); - } - - public Table addInfoTable(Table table){ - return table.table(table1 -> { - table1.left().top(); - - table1.table().update(t -> { - t.clear(); - if(getTarget() instanceof Unit u && u.item() != null) { - if(state.rules.damageExplosions) { - float power = u.item().charge * Mathf.pow(u.stack().amount, 1.11f) * 160f; - int powerAmount = (int)Mathf.clamp(power / 700, 0, 8); - int powerLength = 5 + Mathf.clamp((int)(Mathf.pow(power, 0.98f) / 500), 1, 18); - float powerDamage = 3 + Mathf.pow(power, 0.35f); - - if(powerAmount > 0) { - t.stack( - new Table(tt -> { - tt.image(Icon.power.getRegion()).size(8 * 3f * Scl.scl(modUiScale)); - }), - new Table(tt -> { - tt.right().top(); - Label label = new Label(()->powerAmount + ""); - label.setFontScale(0.75f * Scl.scl(modUiScale)); - tt.add(label).padBottom(4f).padLeft(4f); - tt.pack(); - }) - ).pad(4).visible(() -> state.rules.damageExplosions&&powerAmount > 0); - } - - if(u.item().flammability > 1) { - float flammability = u.item().flammability * u.stack().amount / 1.9f; - int fireAmount = (int)Mathf.clamp(flammability / 4, 0, 30); - t.stack( - new Table(tt -> { - tt.image(StatusEffects.burning.uiIcon).size(8 * 3f * Scl.scl(modUiScale)); - }), - new Table(tt -> { - tt.right().top(); - Label label = new Label(()->fireAmount+""); - label.setFontScale(0.75f * Scl.scl(modUiScale)); - tt.add(label).padBottom(4f).padLeft(4f); - tt.pack(); - }) - ).pad(4).visible(() -> state.rules.damageExplosions&&u.item().flammability > 1); - } - } - - float explosiveness = 2f + u.item().explosiveness * u.stack().amount * 1.53f; - float explosivenessMax = 2f + u.item().explosiveness * u.stack().amount * 1.53f; - int exploAmount = explosiveness <= 2 ? 0 : Mathf.clamp((int)(explosiveness / 11), 1, 25); - int exploAmountMax = explosivenessMax <= 2 ? 0 : Mathf.clamp((int)(explosivenessMax / 11), 1, 25); - float exploRadiusMin = Mathf.clamp(u.bounds() / 2f + explosiveness, 0, 50f) * (1f / exploAmount); - float exploRadiusMax = Mathf.clamp(u.bounds() / 2f + explosiveness, 0, 50f); - float exploDamage = explosiveness / 2f; - - if(exploAmount > 0){ - t.stack( - new Table(tt -> { - tt.image(Icon.modeAttack.getRegion()).size(8 * 3f * Scl.scl(modUiScale)); - }), - new Table(tt -> { - tt.right().top(); - Label label = new Label(()->""+ Strings.fixed(exploDamage * exploAmount, 1)); - label.setFontScale(0.75f * Scl.scl(modUiScale)); - label.setColor(Tmp.c1.set(Color.white).lerp(Pal.health, (exploAmount*1f)/exploAmountMax)); - tt.add(label).padBottom(4f).padLeft(8f); - tt.pack(); - }) - ).pad(4).visible(() -> exploAmount>0); - } - } - }).growX().visible(() -> getTarget() instanceof Unit); - table1.row(); - - float[] count = new float[]{-1}; - table1.table().update(t -> { - if(getTarget() instanceof Payloadc payload){ - if(count[0] != payload.payloadUsed()){ - t.clear(); - t.top().left(); - - float pad = 0; - float items = payload.payloads().size; - if(8 * 2 * items + pad * items > 275f){ - pad = (275f - (8 * 2) * items) / items; - } - int i = 0; - for(Payload p : payload.payloads()){ - t.image(p.icon()).size(8 * 2).padRight(pad); - if(++i % 12 == 0) t.row(); - } - - count[0] = payload.payloadUsed(); - } - }else{ - count[0] = -1; - t.clear(); - } - }).growX().visible(() -> getTarget() instanceof Payloadc p && p.payloadUsed() > 0).colspan(2); - table1.row(); - - Bits statuses = new Bits(); - table1.table().update(t -> { - t.left(); - if(getTarget() instanceof Statusc st){ - Bits applied = st.statusBits(); - if(!statuses.equals(applied)){ - t.clear(); - - if(applied != null){ - for(StatusEffect effect : content.statusEffects()){ - if(applied.get(effect.id) && !effect.isHidden()){ - t.image(effect.uiIcon).size(iconSmall).get().addListener(new Tooltip(l -> l.label(() -> - effect.localizedName + " [lightgray]" + UI.formatTime(st.getDuration(effect))).style(Styles.outlineLabel))); - } - } - statuses.set(applied); - } - } - } - }).left(); - }).get(); - } - - public void addUnitTable(){ - if(uiIndex != 0) return; - unitTable = new Table(table -> { - table.left().defaults().width(Scl.scl(modUiScale) * 35 * 8f).height(Scl.scl(modUiScale) * 35 * 8f); - addBars(); - Table table1 = new Table(Tex.button, t -> { - t.table(Tex.underline2, tt -> { - tt.setWidth(Scl.scl(modUiScale) * 35 * 8f); - Stack stack = new Stack(){{ - add(new Table(ttt -> { - ttt.image(() -> { - TextureRegion region = clear; - if(getTarget() instanceof Unit u && u.type != null) region = u.type.uiIcon; - else if(getTarget() instanceof Building b) { - if(getTarget() instanceof ConstructBlock.ConstructBuild cb) region = cb.current.uiIcon; - else if(b.block != null) region = b.block.uiIcon; - } - return region; - }).size(Scl.scl(modUiScale) * 4 * 8f); - })); - - add(new Table(ttt -> { - ttt.stack( - new Table(temp -> { - temp.image(new ScaledNinePatchDrawable(new NinePatch(Icon.defenseSmall.getRegion()), modUiScale)); - temp.visibility = () -> getTarget() instanceof Unit; - }), - new Table(temp -> { - Label label = new Label(() -> (getTarget() instanceof Unit u && u.type != null ? (int) u.type.armor + "" : "")); - label.setColor(Pal.surge); - label.setFontScale(Scl.scl(modUiScale) * 0.5f); - temp.add(label).center(); - temp.pack(); - }) - ).padLeft(Scl.scl(modUiScale) * 2 * 8f).padBottom(Scl.scl(modUiScale) * 2 * 8f); - })); - }}; - - Label label = new Label(() -> { - String name = ""; - if(getTarget() instanceof Unit u && u.type != null) - name = u.type.localizedName; - if(getTarget() instanceof Building b && b.block != null) { - if(getTarget() instanceof ConstructBlock.ConstructBuild cb) name = cb.current.localizedName; - else name = b.block.localizedName; - } - return "[accent]" + (name.length() > 13 ? name.substring(0, 13) + "..." : name) + "[]"; - }); - label.setFontScale(Scl.scl(modUiScale) * 0.75f); - - TextButton button = Elem.newButton("?", Styles.clearPartialt, () -> { - if(getTarget() instanceof Unit u && u.type != null) - ui.content.show(u.type); - if(getTarget() instanceof Building b && b.block != null) { - ui.content.show(b.block); - } - }); - button.visibility = () -> getTarget() != null; - button.update(() -> { - lockButton.getStyle().imageUp = Icon.lock.tint(locked ? Pal.accent : Color.white); - }); - button.getLabel().setFontScale(Scl.scl(modUiScale)); - - lockButton = Elem.newImageButton(Styles.clearPartiali, Icon.lock.tint(locked ? Pal.accent : Color.white), 3 * 8f * Scl.scl(modUiScale), () -> { - locked = !locked; - lockedTarget = locked ? getTarget() : null; - }); - lockButton.visibility = () -> !getTarget().isNull(); - - tt.top(); - tt.add(stack); - tt.add(label); - tt.add(button).size(Scl.scl(modUiScale) * 3 * 8f); - tt.add(lockButton); - - tt.addListener(new Tooltip(tool -> tool.background(Tex.button).table(to -> { - to.table(Tex.underline2, tool2 -> { - Label label2 = new Label(()->{ - if(getTarget() instanceof Unit u){ - if(u.isPlayer()) return u.getPlayer().name; - if(u.type != null) return u.type.localizedName; - } - else if(getTarget() instanceof Building b) return b.block.localizedName; - return ""; - }); - label2.setFontScale(Scl.scl(modUiScale)); - tool2.add(label2); - }); - to.row(); - Label label2 = new Label(()->getTarget() == null ? "(" + 0 + ", " + 0 + ")" : "(" + Strings.fixed(getTarget().x() / tilesize, 2) + ", " + Strings.fixed(getTarget().y() / tilesize, 2) + ")"); - label2.setFontScale(Scl.scl(modUiScale)); - to.add(label2); - }))); - tt.update(() -> { - tt.setBackground(((NinePatchDrawable)Tex.underline2).tint(getTarget().isNull() ? Color.gray : getTarget().team().color)); - }); - }); - t.row(); - ScrollPane pane = t.pane(Styles.nonePane, new Table(tt -> { - for(Element bar : bars){ - bar.setScale(Scl.scl(modUiScale)); - tt.add(bar).growX().left(); - tt.row(); - } - tt.row(); - addWeaponTable(tt); - }).left()).get(); - pane.update(() -> { - Element result = scene.hit(input.mouseX(), input.mouseY(), true); - if(pane.hasScroll() && (result == null || !result.isDescendantOf(pane))) - scene.setScrollFocus(null); - weaponScrollPos = pane.getScrollY(); - }); - - pane.setOverscroll(false, false); - pane.setScrollingDisabled(true, false); - pane.setScrollYForce(weaponScrollPos); - - t.update(() -> { - NinePatchDrawable patch = (NinePatchDrawable)Tex.button; - t.setBackground(patch.tint(Tmp.c1.set(patch.getPatch().getColor()).a(settings.getInt("uiopacity") / 100f))); - }); - }); - table.table(t -> t.stack(table1, addInfoTable(t)).padRight(Scl.scl(modUiScale) * 8 * 8f)); - - table.update(() -> { - try { - BarInfo.getInfo(getTarget()); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - strings = BarInfo.strings; - numbers = BarInfo.numbers; - colors = BarInfo.colors; - }); - - table.visibility = () -> uiIndex == 0; - }); - } - - public void setWave(Table table){ - int winWave = state.isCampaign() && state.rules.winWave > 0 ? state.rules.winWave : Integer.MAX_VALUE; - waveamount = settings.getInt("wavemax"); - for(int i = settings.getBool("pastwave") ? 0 : state.wave - 1; i <= Math.min(state.wave + waveamount, winWave - 2); i++){ - final int j = i; - if(!settings.getBool("emptywave") && state.rules.spawns.find(g -> g.getSpawned(j) > 0) == null) continue; - table.table(table1 -> { - table1.defaults().width(Scl.scl(modUiScale) * 30 * 8f); - table1.stack( - new Table(t -> { - Label label = new Label(() -> "[#" + (state.wave == j ? Color.red.toString() : Pal.accent.toString()) + "]" + j + "[]"); - label.setFontScale(Scl.scl(modUiScale)); - t.add(label).padRight(Scl.scl(modUiScale) * 24 * 8f); - }), - new Table(Tex.underline, t -> { - t.marginLeft(Scl.scl(modUiScale) * 3 * 8f); - if(settings.getBool("emptywave") && state.rules.spawns.find(g -> g.getSpawned(j) > 0) == null) { - t.center(); - Label label = new Label("[lightgray][]"); - label.setFontScale(Scl.scl(modUiScale)); - t.add(label); - return; - } - - ObjectIntMap groups = new ObjectIntMap<>(); - for(SpawnGroup group : state.rules.spawns) { - if(group.getSpawned(j) <= 0) continue; - SpawnGroup sameTypeKey = groups.keys().toArray().find(g -> g.type == group.type && g.effect != StatusEffects.boss); - if(sameTypeKey != null) groups.increment(sameTypeKey, sameTypeKey.getSpawned(j)); - else groups.put(group, group.getSpawned(j)); - } - Seq groupSorted = groups.keys().toArray().copy().sort((g1, g2) -> { - int boss = Boolean.compare(g1.effect != StatusEffects.boss, g2.effect != StatusEffects.boss); - if(boss != 0) return boss; - int hitSize = Float.compare(-g1.type.hitSize, -g2.type.hitSize); - if(hitSize != 0) return hitSize; - return Integer.compare(-g1.type.id, -g2.type.id); - }); - ObjectIntMap groupsTmp = new ObjectIntMap<>(); - groupSorted.each(g -> groupsTmp.put(g, groups.get(g))); - - int row = 0; - for(SpawnGroup group : groupsTmp.keys()){ - int spawners = state.rules.waveTeam.cores().size + (group.type.flying ? spawner.countFlyerSpawns() : spawner.countGroundSpawns()); - int amount = groupsTmp.get(group); - t.table(tt -> { - Image image = new Image(group.type.uiIcon).setScaling(Scaling.fit); - tt.stack( - new Table(ttt -> { - ttt.center(); - ttt.add(image).size(iconMed * Scl.scl(modUiScale)); - ttt.pack(); - }), - - new Table(ttt -> { - ttt.bottom().left(); - Label label = new Label(() -> amount + ""); - label.setFontScale(Scl.scl(modUiScale) * 0.9f); - Label multi = new Label(() -> "[gray]x" + spawners); - multi.setFontScale(Scl.scl(modUiScale) * 0.8f); - ttt.add(label).padTop(2f); - ttt.add(multi).padTop(10f); - ttt.pack(); - }), - - new Table(ttt -> { - ttt.top().right(); - Image image1 = new Image(Icon.warning.getRegion()).setScaling(Scaling.fit); - image1.update(() -> { - image1.setColor(Tmp.c2.set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time, 2f, 1f))); - }); - ttt.add(image1).size(Scl.scl(modUiScale) * 12f); - ttt.visible(() -> group.effect == StatusEffects.boss); - ttt.pack(); - }) - ).pad(2f * Scl.scl(modUiScale)); - tt.clicked(() -> { - if(input.keyDown(KeyCode.shiftLeft) && Fonts.getUnicode(group.type.name) != 0){ - app.setClipboardText((char)Fonts.getUnicode(group.type.name) + ""); - ui.showInfoFade("@copied"); - }else{ - ui.content.show(group.type); - } - }); - if(!mobile){ - HandCursorListener listener = new HandCursorListener(); - tt.addListener(listener); - tt.update(() -> { - image.color.lerp(!listener.isOver() ? Color.lightGray : Color.white, Mathf.clamp(0.4f * Time.delta)); - }); - } - tt.addListener(new Tooltip(ttt -> ttt.table(Styles.black6, to -> { - to.margin(4f).left(); - to.add("[stat]" + group.type.localizedName + "[]").row(); - to.row(); - to.add(bundle.format("shar-stat-waveAmount", amount + " [lightgray]x" + spawners + "[]")).row(); - to.add(bundle.format("shar-stat-waveShield", group.getShield(j))).row(); - if(group.effect != null && group.effect != StatusEffects.none) - to.add(bundle.get("shar-stat.waveStatus") + group.effect.emoji() + "[stat]" + group.effect.localizedName).row(); - }))); - }); - if(++row % 4 == 0) t.row(); - } - }) - ); - }); - table.row(); - } - } - - public void addWaveTable(){ - if(uiIndex != 1) return; - waveTable = new Table(table -> { - table.defaults().width(Scl.scl(modUiScale) * 35 * 8f).height(35f * 8f * Scl.scl(modUiScale)); - table.add(new Table(Tex.button, t -> { - ScrollPane pane = t.pane(new ScrollPane.ScrollPaneStyle(){{ - vScroll = Tex.clear; - vScrollKnob = new ScaledNinePatchDrawable(new NinePatch(((TextureRegionDrawable) scrollKnobVerticalThin).getRegion()), modUiScale); - }}, new Table(this::setWave)).get(); - pane.update(() -> { - - if(pane.hasScroll()){ - Element result = scene.hit(input.mouseX(), input.mouseY(), true); - if(result == null || !result.isDescendantOf(pane)){ - scene.setScrollFocus(null); - } - } - waveScrollPos = pane.getScrollY(); - if(waveamount != settings.getInt("wavemax")) - pane.setWidget(new Table(this::setWave)); - }); - pane.setOverscroll(false, false); - pane.setScrollingDisabled(true, false); - pane.setScrollYForce(waveScrollPos); - - t.update(() -> { - NinePatchDrawable patch = (NinePatchDrawable)Tex.button; - t.setBackground(patch.tint(Tmp.c1.set(patch.getPatch().getColor()).a(settings.getInt("uiopacity") / 100f))); - }); - })).padRight(Scl.scl(modUiScale) * 72 * 8f); - - table.fillParent = true; - table.visibility = () -> uiIndex == 1; - }); - } - - public void setItem(Table table){ - table.table().update(t -> { - t.clear(); - for(int i = 0; i < coreItems.tables.size; i++){ - if((state.rules.pvp && coreItems.teams[i] != player.team()) || coreItems.teams[i].cores().isEmpty()) continue; - int finalI = i; - t.table(tt -> { - tt.center().defaults().width(Scl.scl(modUiScale) * 44 * 8f); - coreItems.tables.get(finalI).setBackground(((NinePatchDrawable)Tex.underline2).tint(coreItems.teams[finalI].color)); - tt.add(coreItems.tables.get(finalI)).left(); - }).pad(4); - t.row(); - } - }); - } - - public void addItemTable(){ - if(uiIndex != 2) return; - itemTable = new Table(table -> { - table.left().defaults().height(35f * 8f * Scl.scl(modUiScale)); - table.table(Tex.button, t -> { - ScrollPane pane = t.pane(new ScrollPane.ScrollPaneStyle(){{ - vScroll = Tex.clear; - vScrollKnob = new ScaledNinePatchDrawable(new NinePatch(((TextureRegionDrawable) scrollKnobVerticalThin).getRegion()), modUiScale * 0.75f); - }}, new Table(this::setItem).left()).get(); - pane.update(() -> { - Element result = scene.hit(input.mouseX(), input.mouseY(), true); - if(pane.hasScroll() && (result == null || !result.isDescendantOf(pane))) - scene.setScrollFocus(null); - itemScrollPos = pane.getScrollY(); - }); - pane.setOverscroll(false, false); - pane.setScrollingDisabled(true, false); - pane.setScrollYForce(itemScrollPos); - - t.update(() -> { - NinePatchDrawable patch = (NinePatchDrawable)Tex.button; - t.setBackground(patch.tint(Tmp.c1.set(patch.getPatch().getColor()).a(settings.getInt("uiopacity") / 100f))); - }); - }).padRight(Scl.scl(modUiScale) * 39 * 8f); - - table.fillParent = true; - table.visibility = () -> uiIndex == 2; - }); - } } diff --git a/src/UnitInfo/core/Main.java b/src/UnitInfo/core/Main.java index 243445f..363d364 100644 --- a/src/UnitInfo/core/Main.java +++ b/src/UnitInfo/core/Main.java @@ -39,8 +39,6 @@ public class Main extends Mod { Events.on(ClientLoadEvent.class, e -> { new SettingS().init(); hud = new HudUi(); - hud.addWaveTable(); - hud.addUnitTable(); hud.addTable(); hud.addWaveInfoTable(); hud.addSchemTable(); @@ -48,68 +46,5 @@ public class Main extends Mod { OverDrawer.setEvent(); if(jsonGen) ContentJSON.save(); }); - - Events.on(WorldLoadEvent.class, e -> { - hud = new HudUi(); - hud.addWaveTable(); - }); - - Events.on(WaveEvent.class, e -> { - Vars.ui.hudGroup.removeChild(hud.waveTable); - hud = new HudUi(); - hud.addWaveTable(); - }); - - Events.run(Trigger.update, () -> { - if((input.keyDown(KeyCode.shiftRight) || input.keyDown(KeyCode.shiftLeft))){ - if(input.keyTap(KeyCode.h)) { - mmid_playMusicSeq(mmid_parseMusicString(Fi.get("C:/Users/user/Desktop/test/output.txt").readString()), null); - }; - if(input.keyTap(KeyCode.c)) { - schedules.each(Timer.Task::cancel); - } - } - }); - } - - Seq mmid_parseMusicString(String s) { - String[] notes = s.split(";"); - Seq output = new Seq(); - for (String value : notes) { - String[] note = value.split(","); - if (note.length > 0) { - output.add(new Float[]{ - Float.parseFloat(note[0]), - (note.length < 2 || note[1] == null) ? 0 : Float.parseFloat(note[1]), - (note.length < 3 || note[2] == null) ? 0 : Float.parseFloat(note[2]), - (note.length < 4 || note[3] == null) ? 1 : Float.parseFloat(note[3]), - (note.length < 5 || note[4] == null) ? 0 : Float.parseFloat(note[4]) - }); - } - } - Log.info(output); - return output; - }; - - Seq schedules = new Seq<>(); - void mmid_playMusicSeq(Seq s, @Nullable Player p) { - Object[][] mmid_instruments = { //Sound, pitch, volume - {Sounds.minebeam, 0.98f, 20f}, - {Sounds.minebeam, 2.2f, 0.5f}}; - - s.each(n-> { - schedules.add(Timer.schedule(() -> { - Log.info(mmid_instruments[n[2].intValue()][0].toString() + " sound is called"); - if(p == null || p.con == null) Call.sound( - (Sound)mmid_instruments[n[2].intValue()][0], - n[3]*(float)mmid_instruments[n[2].intValue()][2], - (float)mmid_instruments[n[2].intValue()][1]*(float)Math.pow(1.0595,n[1]), n[4]); - else Call.sound(p.con, - (Sound)mmid_instruments[n[2].intValue()][0], - n[3]*(float)mmid_instruments[n[2].intValue()][2], - (float)mmid_instruments[n[2].intValue()][1]*1f*(float)Math.pow(1.0595,n[1]), n[4]); - },n[0])); - Log.info("start sound after" + n[0] + "sec"); - }); } } diff --git a/src/UnitInfo/core/OverDrawer.java b/src/UnitInfo/core/OverDrawer.java index 76b9ca1..33e70f7 100644 --- a/src/UnitInfo/core/OverDrawer.java +++ b/src/UnitInfo/core/OverDrawer.java @@ -48,14 +48,14 @@ public class OverDrawer { public static int otherCores; public static boolean locked; public static ObjectMap> tmpbuildobj = new ObjectMap<>(); - public static ObjectMap> tmpunitobj = new ObjectMap<>(); + + static float sin = Mathf.absin(Time.time, 6f, 1f); public static void setEvent(){ Events.run(EventType.Trigger.draw, () -> { + + effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); - - float sin = Mathf.absin(Time.time, 6f, 1f); - Draw.drawRange(158, 1f, () -> effectBuffer.begin(Color.clear), () -> { effectBuffer.end(); effectBuffer.blit(lineShader); @@ -125,7 +125,7 @@ public class OverDrawer { pathTiles.clear(); } }); - + Draw.reset(); Draw.z(Layer.overlayUI); int[] arrows = {0}; @@ -203,7 +203,7 @@ public class OverDrawer { Pal.accent, 0.25f * unit.itemTime / Scl.scl(1f), false, Align.center) ); - if(!state.rules.polygonCoreProtection && settings.getBool("coreRange") && player != null){ + if(!state.rules.polygonCoreProtection && player != null){ state.teams.eachEnemyCore(player.team(), core -> { if(Core.camera.bounds(Tmp.r1).overlaps(Tmp.r2.setCentered(core.x, core.y, state.rules.enemyCoreBuildRadius * 2f))){ Draw.color(Color.darkGray); @@ -265,6 +265,8 @@ public class OverDrawer { Unit unit = player.unit(); tmpbuildobj.clear(); for(int i = 0; i < Team.baseTeams.length; i++){ + if(!settings.getBool("aliceRange") && player.team() == Team.baseTeams[i]) continue; + int finalI = i; tmpbuildobj.put(Team.baseTeams[i], Groups.build.copy(new Seq()).filter(b -> { if(!(b instanceof BaseTurret.BaseTurretBuild)) return false; @@ -282,7 +284,7 @@ public class OverDrawer { })); } tmpbuildobj.each((t, bseq) -> { - Draw.drawRange(166+t.id*3, 1, () -> effectBuffer.begin(Color.clear), () -> { + if(settings.getBool("RangeShader")) Draw.drawRange(166+t.id*3, 1, () -> effectBuffer.begin(Color.clear), () -> { effectBuffer.end(); effectBuffer.blit(turretRange); }); @@ -293,10 +295,11 @@ public class OverDrawer { Draw.z(166+t.id*3); Fill.poly(b.x, b.y, Lines.circleVertices(range), range); } - else Lines.circle(b.x, b.y, range); + else Drawf.dashCircle(b.x, b.y, range, t.color); }); }); } + Draw.reset(); }); } diff --git a/src/UnitInfo/core/SettingS.java b/src/UnitInfo/core/SettingS.java index 7576a62..6f72d18 100644 --- a/src/UnitInfo/core/SettingS.java +++ b/src/UnitInfo/core/SettingS.java @@ -113,13 +113,14 @@ public class SettingS { addGraphicCheckSetting("infoui", true, tapSeq); addGraphicCheckSetting("pastwave", false, tapSeq); addGraphicCheckSetting("emptywave", true, tapSeq); + addGraphicCheckSetting("itemcal", false, tapSeq); Seq rangeSeq = new Seq<>(); addGraphicTypeSetting("rangeRadius", 0, 500, 70, true, () -> true, s -> s + "tiles", rangeSeq); addGraphicCheckSetting("rangeNearby", true, rangeSeq); addGraphicCheckSetting("allTargetRange", false, rangeSeq); - addGraphicCheckSetting("coreRange", false, rangeSeq); - addGraphicCheckSetting("RangeShader", true, rangeSeq); + addGraphicCheckSetting("aliceRange", false, rangeSeq); + addGraphicCheckSetting("RangeShader", false, rangeSeq); Seq opacitySeq = new Seq<>(); addGraphicSlideSetting("selectopacity", 50, 0, 100, 5, s -> s + "%", opacitySeq); diff --git a/src/UnitInfo/ui/CoreDisplay.java b/src/UnitInfo/ui/CoreDisplay.java new file mode 100644 index 0000000..b563e21 --- /dev/null +++ b/src/UnitInfo/ui/CoreDisplay.java @@ -0,0 +1,71 @@ +package UnitInfo.ui; + +import UnitInfo.SVars; +import arc.graphics.g2d.NinePatch; +import arc.scene.Element; +import arc.scene.style.*; +import arc.scene.ui.ScrollPane; +import arc.scene.ui.layout.*; +import arc.util.*; +import mindustry.gen.Tex; +import mindustry.ui.Styles; + +import static UnitInfo.SVars.modUiScale; +import static arc.Core.*; +import static mindustry.Vars.*; + +public class CoreDisplay extends Table { + static float itemScrollPos, heat; + static Table table = new Table(); + + public CoreDisplay() { + fillParent = true; + visibility = () -> 2 == SVars.hud.uiIndex; + + left().defaults().height(35f * 8f * Scl.scl(modUiScale)); + table(Tex.button, t -> { + ScrollPane pane = t.pane(Styles.nonePane, rebuild()).get(); + pane.update(() -> { + Element result = scene.hit(input.mouseX(), input.mouseY(), true); + if(pane.hasScroll() && (result == null || !result.isDescendantOf(pane))) + scene.setScrollFocus(null); + itemScrollPos = pane.getScrollY(); + }); + pane.setOverscroll(false, false); + pane.setScrollingDisabled(true, false); + pane.setScrollYForce(itemScrollPos); + + t.update(() -> { + NinePatchDrawable patch = (NinePatchDrawable)Tex.button; + t.setBackground(patch.tint(Tmp.c1.set(patch.getPatch().getColor()).a(settings.getInt("uiopacity") / 100f))); + }); + }).padRight(Scl.scl(modUiScale) * 39 * 8f); + } + + public void setEvent() { + heat += Time.delta; + + if(heat > 60f) { + heat = 0f; + rebuild(); + } + } + + public Table rebuild() { + table.clear(); + table.table(t -> { + for(int i = 0; i < CoresItemsDisplay.tables.size; i++){ + if((state.rules.pvp && CoresItemsDisplay.teams[i] != player.team()) || CoresItemsDisplay.teams[i].cores().isEmpty()) continue; + int finalI = i; + t.table(tt -> { + tt.center().defaults().width(Scl.scl(modUiScale) * 44 * 8f); + CoresItemsDisplay.tables.get(finalI).setBackground(((NinePatchDrawable)Tex.underline2).tint(CoresItemsDisplay.teams[finalI].color)); + tt.add(CoresItemsDisplay.tables.get(finalI)).left(); + }).pad(4); + t.row(); + } + }); + + return table; + } +} diff --git a/src/UnitInfo/ui/CoresItemsDisplay.java b/src/UnitInfo/ui/CoresItemsDisplay.java index 4a63fb7..19329e2 100644 --- a/src/UnitInfo/ui/CoresItemsDisplay.java +++ b/src/UnitInfo/ui/CoresItemsDisplay.java @@ -25,19 +25,18 @@ import static arc.Core.*; import static mindustry.Vars.*; public class CoresItemsDisplay { - private final ObjectMap> usedItems = new ObjectMap<>(); - private final ObjectMap> usedUnits = new ObjectMap<>(); - private final ObjectMap> prevItems = new ObjectMap<>(); - private final ObjectMap> updateItems = new ObjectMap<>(); - public final ObjectIntMap coreAmount = new ObjectIntMap<>(); - private CoreBlock.CoreBuild core; - public Team[] teams; - public Seq tables = new Seq<>(); + static final ObjectMap> usedItems = new ObjectMap<>(); + static final ObjectMap> usedUnits = new ObjectMap<>(); + static final ObjectMap> prevItems = new ObjectMap<>(); + static final ObjectMap> updateItems = new ObjectMap<>(); + static final ObjectIntMap coreAmount = new ObjectIntMap<>(); + static CoreBlock.CoreBuild core; + static Seq
tables = new Seq<>(); - float heat; + static Team[] teams; + static float heat; - public CoresItemsDisplay(Team[] teams) { - this.teams = teams; + public CoresItemsDisplay() { resetUsed(); } @@ -77,12 +76,16 @@ public class CoresItemsDisplay { return new Table(t -> { t.update(() -> { core = team.core(); - heat += Time.delta; - if(heat >= settings.getInt("coreItemCheckRate")) { - heat = 0; - updateItem(team); + if(settings.getBool("itemcal")) { + heat += Time.delta; + + if(heat >= settings.getInt("coreItemCheckRate")) { + heat = 0; + updateItem(team); + } } + if(coreAmount.get(team) != team.cores().size){ coreAmount.put(team, team.cores().size); rebuild(); @@ -139,14 +142,16 @@ public class CoresItemsDisplay { final int[] i = {0}; for(Item item : content.items()){ if(team.core() != null && team.core().items.has(item)) { - itemTable.stack( - new Table(ttt -> { - ttt.image(item.uiIcon).size(iconSmall * modUiScale).tooltip(tttt -> tttt.background(Styles.black6).margin(2f * modUiScale).add(item.localizedName).style(Styles.outlineLabel)); - Label label = new Label(() -> core == null ? "0" : UI.formatAmount(core.items.get(item))); - label.setFontScale(modUiScale); - ttt.add(label).minWidth(5 * 8f * modUiScale).left(); - }), - new Table(ttt -> { + Table table1 = new Table(ttt -> { + ttt.image(item.uiIcon).size(iconSmall * modUiScale).tooltip(tttt -> tttt.background(Styles.black6).margin(2f * modUiScale).add(item.localizedName).style(Styles.outlineLabel)); + Label label = new Label(() -> core == null ? "0" : UI.formatAmount(core.items.get(item))); + label.setFontScale(modUiScale); + ttt.add(label).minWidth(5 * 8f * modUiScale).left(); + }); + + + if(settings.getBool("itemcal")) { + Table table2 = new Table(ttt -> { ttt.bottom().right(); Label label = new Label(() -> { int amount = (int)(updateItems.get(team).get(item.id).amount / ((settings.getInt("coreItemCheckRate") * 1f) / 60f)); @@ -155,8 +160,11 @@ public class CoresItemsDisplay { label.setFontScale(0.65f * modUiScale); ttt.add(label).bottom().right().padTop(16f * modUiScale); ttt.pack(); - }) - ).padRight(3 * modUiScale).left(); + }); + + itemTable.stack(table1, table2).padRight(3 * modUiScale).left(); + } + else itemTable.add(table1).padRight(3 * modUiScale).left(); if(++i[0] % 5 == 0) itemTable.row(); } } diff --git a/src/UnitInfo/ui/SchemDisplay.java b/src/UnitInfo/ui/SchemDisplay.java new file mode 100644 index 0000000..7a79a59 --- /dev/null +++ b/src/UnitInfo/ui/SchemDisplay.java @@ -0,0 +1,488 @@ +package UnitInfo.ui; + +import UnitInfo.SUtils; +import arc.Core; +import arc.func.Cons; +import arc.func.Floatf; +import arc.graphics.Color; +import arc.input.KeyCode; +import arc.scene.Element; +import arc.scene.style.TextureRegionDrawable; +import arc.scene.ui.*; +import arc.scene.ui.layout.*; +import arc.scene.utils.Elem; +import arc.struct.Seq; +import arc.util.Align; +import arc.util.*; +import mindustry.ctype.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.graphics.Pal; +import mindustry.ui.Styles; +import mindustry.ui.dialogs.*; + +import static arc.Core.input; +import static arc.Core.scene; +import static mindustry.Vars.*; +import static mindustry.Vars.ui; + +public class SchemDisplay extends Table { + static float schemScrollPos, tagScrollPos; + static boolean schemShown; + static Schematic firstSchematic; + static final Seq selectedTags = new Seq<>(); + static Runnable rebuildList = () -> {}; + + public SchemDisplay() { + setSchemTable(); + } + + + void setSchemTable() { + clear(); + right(); + button("Schematic List", Icon.downOpen, Styles.squareTogglet, () -> schemShown = !schemShown).width(160f).height(60f).checked(b -> { + Image image = (Image)b.getCells().first().get(); + image.setDrawable(schemShown ? Icon.upOpen : Icon.downOpen); + return schemShown; + }).row(); + collapser(t -> { + t.background(Styles.black8).defaults().maxHeight(72 * 8f).maxWidth(160f); + rebuildList = () -> { + t.clearChildren(); + ScrollPane pane1 = t.pane(Styles.nonePane, p -> { + p.left().defaults().pad(2).height(42f); + try { + for(String tag : (Seq)SUtils.invoke(ui.schematics, "tags")){ + p.button(tag, Styles.togglet, () -> { + if(selectedTags.contains(tag)){ + selectedTags.remove(tag); + }else{ + selectedTags.add(tag); + } + rebuildList.run(); + }).checked(selectedTags.contains(tag)).with(c -> c.getLabel().setWrap(false)); + } + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + }).fillX().height(42f).get(); + pane1.update(() -> { + Element result = scene.hit(input.mouseX(), input.mouseY(), true); + if(pane1.hasScroll() && (result == null || !result.isDescendantOf(pane1))) + scene.setScrollFocus(null); + tagScrollPos = pane1.getScrollX(); + }); + + pane1.setOverscroll(false, false); + pane1.setScrollingDisabled(false, true); + pane1.setScrollXForce(tagScrollPos); + + t.row(); + + ScrollPane pane = t.pane(Styles.nonePane, p -> { + p.table(tt -> { + firstSchematic = null; + + tt.button("Import", Icon.download, this::showImport).width(160f).height(64f).row(); + for(Schematic s : schematics.all()){ + if(selectedTags.any() && !s.labels.containsAll(selectedTags)) continue; + if(firstSchematic == null) firstSchematic = s; + + Button[] sel = {null}; + sel[0] = tt.button(b -> { + b.top(); + b.margin(0f); + b.table(buttons -> { + buttons.left(); + buttons.defaults().size(162/4f); + + ImageButton.ImageButtonStyle style = Styles.clearPartiali; + + buttons.button(Icon.info, style, () -> showInfo(s)); + buttons.button(Icon.upload, style, () -> showExport(s)); + buttons.button(Icon.pencil, style, () -> { + new Dialog("@schematic.rename"){{ + setFillParent(true); + + cont.margin(30); + + cont.add("@schematic.tags").padRight(6f); + cont.table(tags -> buildTags(s, tags, false)).maxWidth(400f).fillX().left().row(); + + cont.margin(30).add("@name").padRight(6f); + TextField nameField = cont.field(s.name(), null).size(400f, 55f).left().get(); + + cont.row(); + + cont.margin(30).add("@editor.description").padRight(6f); + TextField descField = cont.area(s.description(), Styles.areaField, t -> {}).size(400f, 140f).left().get(); + + Runnable accept = () -> { + s.tags.put("name", nameField.getText()); + s.tags.put("description", descField.getText()); + s.save(); + hide(); + setSchemTable(); + }; + + buttons.defaults().size(120, 54).pad(4); + buttons.button("@ok", accept).disabled(b -> nameField.getText().isEmpty()); + buttons.button("@cancel", this::hide); + + keyDown(KeyCode.enter, () -> { + if(!nameField.getText().isEmpty() && Core.scene.getKeyboardFocus() != descField){ + accept.run(); + } + }); + keyDown(KeyCode.escape, this::hide); + keyDown(KeyCode.back, this::hide); + show(); + }}; + }); + + if(s.hasSteamID()){ + buttons.button(Icon.link, style, () -> platform.viewListing(s)); + }else{ + buttons.button(Icon.trash, style, () -> { + if(s.mod != null){ + ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.displayName())); + }else{ + ui.showConfirm("@confirm", "@schematic.delete.confirm", () -> { + schematics.remove(s); + setSchemTable(); + }); + } + }); + } + + }).growX().height(50f); + b.row(); + b.stack(new SchematicsDialog.SchematicImage(s).setScaling(Scaling.fit), new Table(n -> { + n.top(); + n.table(Styles.black3, c -> { + Label label = c.add(s.name()).style(Styles.outlineLabel).color(Color.white).top().growX().maxWidth(200f - 8f).get(); + label.setEllipsis(true); + label.setAlignment(Align.center); + }).growX().margin(1).pad(4).maxWidth(Scl.scl(160f - 8f)).padBottom(0); + })).size(160f); + }, () -> { + if(sel[0].childrenPressed()) return; + control.input.useSchematic(s); + + }).pad(4).style(Styles.cleari).get(); + + sel[0].getStyle().up = Tex.pane; + tt.row(); + } + + if(firstSchematic == null){ + tt.add("@none"); + } + }); + }).grow().get(); + + pane.update(() -> { + Element result = scene.hit(input.mouseX(), input.mouseY(), true); + if(pane.hasScroll() && (result == null || !result.isDescendantOf(pane))) + scene.setScrollFocus(null); + schemScrollPos = pane.getScrollY(); + }); + + pane.setOverscroll(false, false); + pane.setScrollingDisabled(true, false); + pane.setScrollYForce(schemScrollPos); + }; + rebuildList.run(); + }, true, () -> schemShown); + } + + void showInfo(Schematic schematic){ + try { + ((SchematicsDialog.SchematicInfoDialog) SUtils.invoke(ui.schematics, "info")).show(schematic); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + void checkTags(Schematic s){ + boolean any = false; + Seq seq = null; + try { + seq = (Seq) SUtils.invoke(ui.schematics, "tags"); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + if(seq == null) return; + for(var tag : s.labels){ + if(!seq.contains(tag)){ + seq.add(tag); + any = true; + } + } + if(any) setSchemTable(); + } + + void showImport(){ + BaseDialog dialog = new BaseDialog("@editor.export"); + dialog.cont.pane(p -> { + p.margin(10f); + p.table(Tex.button, t -> { + TextButton.TextButtonStyle style = Styles.cleart; + t.defaults().size(280f, 60f).left(); + t.row(); + t.button("@schematic.copy.import", Icon.copy, style, () -> { + dialog.hide(); + try{ + Schematic s = Schematics.readBase64(Core.app.getClipboardText()); + s.removeSteamID(); + schematics.add(s); + setSchemTable(); + ui.showInfoFade("@schematic.saved"); + checkTags(s); + showInfo(s); + }catch(Throwable e){ + ui.showException(e); + } + }).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart)); + t.row(); + t.button("@schematic.importfile", Icon.download, style, () -> platform.showFileChooser(true, schematicExtension, file -> { + dialog.hide(); + + try{ + Schematic s = Schematics.read(file); + s.removeSteamID(); + schematics.add(s); + setSchemTable(); + showInfo(s); + checkTags(s); + }catch(Exception e){ + ui.showException(e); + } + })).marginLeft(12f); + t.row(); + if(steam){ + t.button("@schematic.browseworkshop", Icon.book, style, () -> { + dialog.hide(); + platform.openWorkshop(); + }).marginLeft(12f); + } + }); + }); + + dialog.addCloseButton(); + dialog.show(); + } + + void showExport(Schematic s){ + BaseDialog dialog = new BaseDialog("@editor.export"); + dialog.cont.pane(p -> { + p.margin(10f); + p.table(Tex.button, t -> { + TextButton.TextButtonStyle style = Styles.cleart; + t.defaults().size(280f, 60f).left(); + if(steam && !s.hasSteamID()){ + t.button("@schematic.shareworkshop", Icon.book, style, + () -> platform.publish(s)).marginLeft(12f); + t.row(); + dialog.hide(); + } + t.button("@schematic.copy", Icon.copy, style, () -> { + dialog.hide(); + ui.showInfoFade("@copied"); + Core.app.setClipboardText(schematics.writeBase64(s)); + }).marginLeft(12f); + t.row(); + t.button("@schematic.exportfile", Icon.export, style, () -> { + dialog.hide(); + platform.export(s.name(), schematicExtension, file -> Schematics.write(s, file)); + }).marginLeft(12f); + }); + }); + + dialog.addCloseButton(); + dialog.show(); + } + + void tagsChanged(){ + rebuildList.run(); + Seq tags = null; + try { + tags = (Seq) SUtils.invoke(ui.schematics, "tags"); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + if(tags == null) return; + Core.settings.putJson("schematic-tags", String.class, tags); + } + + void addTag(Schematic s, String tag){ + s.labels.add(tag); + s.save(); + tagsChanged(); + } + + void removeTag(Schematic s, String tag){ + s.labels.remove(tag); + s.save(); + tagsChanged(); + } + + //shows a dialog for creating a new tag + void showNewTag(Cons result){ + Seq tags = null; + try { + tags = (Seq) SUtils.invoke(ui.schematics, "tags"); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + if(tags == null) return; + Seq finalTags = tags; + ui.showTextInput("@schematic.addtag", "", "", out -> { + if(finalTags.contains(out)){ + ui.showInfo("@schematic.tagexists"); + }else{ + finalTags.add(out); + tagsChanged(); + result.get(out); + } + }); + } + + void showNewIconTag(Cons cons){ + Seq tags = null; + try { + tags = (Seq) SUtils.invoke(ui.schematics, "tags"); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + if(tags == null) return; + Seq finalTags = tags; + new Dialog(){{ + closeOnBack(); + setFillParent(true); + + cont.pane(t -> + resized(true, () -> { + t.clearChildren(); + t.marginRight(19f); + t.defaults().size(48f); + + int cols = (int)Math.min(20, Core.graphics.getWidth() / Scl.scl(52f)); + + for(ContentType ctype : defaultContentIcons){ + t.row(); + t.image().colspan(cols).growX().width(Float.NEGATIVE_INFINITY).height(3f).color(Pal.accent); + t.row(); + + int i = 0; + for(UnlockableContent u : content.getBy(ctype).as()){ + if(!u.isHidden() && u.unlockedNow() && u.hasEmoji() && !finalTags.contains(u.emoji())){ + t.button(new TextureRegionDrawable(u.uiIcon), Styles.cleari, iconMed, () -> { + String out = u.emoji() + ""; + + finalTags.add(out); + tagsChanged(); + cons.get(out); + + hide(); + }); + + if(++i % cols == 0) t.row(); + } + } + } + }) + ); + buttons.button("@back", Icon.left, this::hide).size(210f, 64f); + }}.show(); + } + + void buildTags(Schematic schem, Table t, boolean name){ + t.clearChildren(); + t.left(); + Seq tags = null; + try { + tags = (Seq) SUtils.invoke(ui.schematics, "tags"); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + if(tags == null) return; + + //sort by order in the main target array. the complexity of this is probably awful + Seq finalTags = tags; + schem.labels.sort((Floatf) finalTags::indexOf); + + if(name) t.add("@schematic.tags").padRight(4); + t.pane(s -> { + s.left(); + s.defaults().pad(3).height(42f); + for(var tag : schem.labels){ + s.table(Tex.button, i -> { + i.add(tag).padRight(4).height(42f).labelAlign(Align.center); + i.button(Icon.cancelSmall, Styles.emptyi, () -> { + removeTag(schem, tag); + buildTags(schem, t, name); + }).size(42f).padRight(-9f).padLeft(-9f); + }); + } + + }).fillX().left().height(42f).scrollY(false); + + Seq finalTags1 = tags; + t.button(Icon.addSmall, () -> { + var dialog = new BaseDialog("@schematic.addtag"); + dialog.addCloseButton(); + dialog.cont.pane(p -> { + p.clearChildren(); + + float sum = 0f; + Table current = new Table().left(); + for(var tag : finalTags1){ + if(schem.labels.contains(tag)) continue; + + var next = Elem.newButton(tag, () -> { + addTag(schem, tag); + buildTags(schem, t, name); + dialog.hide(); + }); + next.getLabel().setWrap(false); + + next.pack(); + float w = next.getPrefWidth() + Scl.scl(6f); + + if(w + sum >= Core.graphics.getWidth() * (Core.graphics.isPortrait() ? 1f : 0.8f)){ + p.add(current).row(); + current = new Table(); + current.left(); + current.add(next).height(42f).pad(2); + sum = 0; + }else{ + current.add(next).height(42f).pad(2); + } + + sum += w; + } + + if(sum > 0){ + p.add(current).row(); + } + + Cons handleTag = res -> { + dialog.hide(); + addTag(schem, res); + buildTags(schem, t, name); + }; + + p.row(); + + p.table(v -> { + v.left().defaults().fillX().height(42f).pad(2); + v.button("@schematic.texttag", Icon.add, () -> showNewTag(handleTag)).wrapLabel(false).get().getLabelCell().padLeft(4); + v.button("@schematic.icontag", Icon.add, () -> showNewIconTag(handleTag)).wrapLabel(false).get().getLabelCell().padLeft(4); + }); + }); + dialog.show(); + }).size(42f).tooltip("@schematic.addtag"); + } +} diff --git a/src/UnitInfo/ui/UnitDisplay.java b/src/UnitInfo/ui/UnitDisplay.java new file mode 100644 index 0000000..074897f --- /dev/null +++ b/src/UnitInfo/ui/UnitDisplay.java @@ -0,0 +1,465 @@ +package UnitInfo.ui; + +import UnitInfo.SVars; +import UnitInfo.core.BarInfo; +import arc.graphics.Color; +import arc.graphics.g2d.*; +import arc.input.KeyCode; +import arc.math.Mathf; +import arc.math.geom.Rect; +import arc.scene.Element; +import arc.scene.style.*; +import arc.scene.ui.*; +import arc.scene.ui.layout.*; +import arc.scene.utils.Elem; +import arc.struct.Bits; +import arc.struct.Seq; +import arc.util.Strings; +import arc.util.Tmp; +import mindustry.content.StatusEffects; +import mindustry.core.UI; +import mindustry.entities.units.WeaponMount; +import mindustry.gen.*; +import mindustry.graphics.Pal; +import mindustry.type.StatusEffect; +import mindustry.type.Weapon; +import mindustry.ui.Styles; +import mindustry.world.blocks.ConstructBlock; +import mindustry.world.blocks.defense.ForceProjector; +import mindustry.world.blocks.defense.turrets.*; +import mindustry.world.blocks.distribution.MassDriver; +import mindustry.world.blocks.payloads.Payload; +import mindustry.world.blocks.power.*; + +import static UnitInfo.SVars.clear; +import static UnitInfo.SVars.modUiScale; +import static arc.Core.*; +import static mindustry.Vars.*; + +public class UnitDisplay extends Table { + static ImageButton lockButton; + static float weaponScrollPos; + static Seq bars = new Seq<>(); + static Seq lastColors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); + static final Rect scissor = new Rect(); + + public UnitDisplay() { + fillParent = true; + visibility = () -> 0 == SVars.hud.uiIndex; + + left().defaults().width(Scl.scl(modUiScale) * 35 * 8f).height(Scl.scl(modUiScale) * 35 * 8f); + bars.clear(); + for(int i = 0; i < 6; i++) bars.add(addBar(i)); + Table table1 = new Table(Tex.button, t -> { + t.table(Tex.underline2, tt -> { + tt.setWidth(Scl.scl(modUiScale) * 35 * 8f); + Stack stack = new Stack(){{ + add(new Table(ttt -> { + ttt.image(() -> { + TextureRegion region = clear; + if(getTarget() instanceof Unit u && u.type != null) region = u.type.uiIcon; + else if(getTarget() instanceof Building b) { + if(getTarget() instanceof ConstructBlock.ConstructBuild cb) region = cb.current.uiIcon; + else if(b.block != null) region = b.block.uiIcon; + } + return region; + }).size(Scl.scl(modUiScale) * 4 * 8f); + })); + + add(new Table(ttt -> { + ttt.stack( + new Table(temp -> { + temp.image(new ScaledNinePatchDrawable(new NinePatch(Icon.defenseSmall.getRegion()), modUiScale)); + temp.visibility = () -> getTarget() instanceof Unit; + }), + new Table(temp -> { + Label label = new Label(() -> (getTarget() instanceof Unit u && u.type != null ? (int) u.type.armor + "" : "")); + label.setColor(Pal.surge); + label.setFontScale(Scl.scl(modUiScale) * 0.5f); + temp.add(label).center(); + temp.pack(); + }) + ).padLeft(Scl.scl(modUiScale) * 2 * 8f).padBottom(Scl.scl(modUiScale) * 2 * 8f); + })); + }}; + + Label label = new Label(() -> { + String name = ""; + if(getTarget() instanceof Unit u && u.type != null) + name = u.type.localizedName; + if(getTarget() instanceof Building b && b.block != null) { + if(getTarget() instanceof ConstructBlock.ConstructBuild cb) name = cb.current.localizedName; + else name = b.block.localizedName; + } + return "[accent]" + (name.length() > 13 ? name.substring(0, 13) + "..." : name) + "[]"; + }); + label.setFontScale(Scl.scl(modUiScale) * 0.75f); + + TextButton button = Elem.newButton("?", Styles.clearPartialt, () -> { + if(getTarget() instanceof Unit u && u.type != null) + ui.content.show(u.type); + if(getTarget() instanceof Building b && b.block != null) { + ui.content.show(b.block); + } + }); + button.visibility = () -> getTarget() != null; + button.update(() -> lockButton.getStyle().imageUp = Icon.lock.tint(SVars.hud.locked ? Pal.accent : Color.white)); + button.getLabel().setFontScale(Scl.scl(modUiScale)); + + lockButton = Elem.newImageButton(Styles.clearPartiali, Icon.lock.tint(SVars.hud.locked ? Pal.accent : Color.white), 3 * 8f * Scl.scl(modUiScale), () -> { + SVars.hud.locked = !SVars.hud.locked; + SVars.hud.lockedTarget = SVars.hud.locked ? getTarget() : null; + }); + lockButton.visibility = () -> !getTarget().isNull(); + + tt.top(); + tt.add(stack); + tt.add(label); + tt.add(button).size(Scl.scl(modUiScale) * 3 * 8f); + tt.add(lockButton); + + tt.addListener(new Tooltip(tool -> tool.background(Tex.button).table(to -> { + to.table(Tex.underline2, tool2 -> { + Label label2 = new Label(()->{ + if(getTarget() instanceof Unit u){ + if(u.isPlayer()) return u.getPlayer().name; + if(u.type != null) return u.type.localizedName; + } + else if(getTarget() instanceof Building b) return b.block.localizedName; + return ""; + }); + label2.setFontScale(Scl.scl(modUiScale)); + tool2.add(label2); + }); + to.row(); + Label label2 = new Label(()->getTarget() == null ? "(" + 0 + ", " + 0 + ")" : "(" + Strings.fixed(getTarget().x() / tilesize, 2) + ", " + Strings.fixed(getTarget().y() / tilesize, 2) + ")"); + label2.setFontScale(Scl.scl(modUiScale)); + to.add(label2); + }))); + tt.update(() -> tt.setBackground(((NinePatchDrawable)Tex.underline2).tint(getTarget().isNull() ? Color.gray : getTarget().team().color))); + }); + t.row(); + ScrollPane pane = t.pane(Styles.nonePane, new Table(tt -> { + for(Element bar : bars){ + bar.setScale(Scl.scl(modUiScale)); + tt.add(bar).growX().left(); + tt.row(); + } + tt.row(); + tt.add(new WeaponDisplay()); + }).left()).get(); + pane.update(() -> { + Element result = scene.hit(input.mouseX(), input.mouseY(), true); + if(pane.hasScroll() && (result == null || !result.isDescendantOf(pane))) + scene.setScrollFocus(null); + weaponScrollPos = pane.getScrollY(); + }); + + pane.setOverscroll(false, false); + pane.setScrollingDisabled(true, false); + pane.setScrollYForce(weaponScrollPos); + + t.update(() -> { + NinePatchDrawable patch = (NinePatchDrawable)Tex.button; + t.setBackground(patch.tint(Tmp.c1.set(patch.getPatch().getColor()).a(settings.getInt("uiopacity") / 100f))); + }); + }); + table(t -> t.stack(table1, new UnitInfoDisplay()).padRight(Scl.scl(modUiScale) * 8 * 8f)); + + update(() -> { + try { + BarInfo.getInfo(getTarget()); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + }); + } + + public static Teamc getTarget() { + return SVars.hud == null ? null : SVars.hud.getTarget(); + } + + public void setEvent() { + if((input.keyDown(KeyCode.shiftRight) || input.keyDown(KeyCode.shiftLeft))) { + if(input.keyTap(KeyCode.r) && lockButton != null) lockButton.change(); + } + } + + public TextureRegion getRegions(int i){ + Teamc target = getTarget(); + TextureRegion region = clear; + + if(i == 0){ + if(target instanceof Healthc) region = SIcons.health; + } else if(i == 1){ + if(target instanceof Turret.TurretBuild || + target instanceof MassDriver.MassDriverBuild){ + region = SIcons.reload; + } else if((target instanceof Unit unit && unit.type != null) || + target instanceof ForceProjector.ForceBuild){ + region = SIcons.shield; + } else if(target instanceof PowerNode.PowerNodeBuild || + target instanceof PowerGenerator.GeneratorBuild){ + region = SIcons.power; + } + } else if(i == 2){ + if(target instanceof ItemTurret.ItemTurretBuild){ + region = SIcons.ammo; + } else if(target instanceof LiquidTurret.LiquidTurretBuild){ + region = SIcons.liquid; + } else if(target instanceof PowerTurret.PowerTurretBuild || + target instanceof PowerNode.PowerNodeBuild){ + region = SIcons.power; + } else if((target instanceof Building b && b.block.hasItems) || + (target instanceof Unit unit && unit.type != null)){ + region = SIcons.item; + } + } else if(i == 3){ + if(target instanceof PowerNode.PowerNodeBuild){ + region = SIcons.power; + } + } else if(i == 4){ + if(target instanceof PowerNode.PowerNodeBuild){ + region = SIcons.power; + } else if(target instanceof Building b && b.block.hasLiquids){ + region = SIcons.liquid; + } + } else if(i == 5){ + if(target instanceof Unit unit && state.rules.unitAmmo && unit.type != null){ + region = SIcons.ammo; + }else if(target instanceof PowerNode.PowerNodeBuild || + (target instanceof Building b && b.block.consumes.hasPower())){ + region = SIcons.power; + } + } + + return region; + } + + public Element addBar(int i){ + return new Stack(){{ + add(new Table(t -> { + t.add(new SBar( + () -> BarInfo.strings.get(i), + () -> { + if (BarInfo.colors.get(i) != Color.clear) lastColors.set(i, BarInfo.colors.get(i)); + return lastColors.get(i); + }, + () -> BarInfo.numbers.get(i) + )).width(Scl.scl(modUiScale) * 24 * 8f).height(Scl.scl(modUiScale) * 4 * 8f).growX().left(); + })); + add(new Table(t -> { + t.right(); + t.add(new Image(){ + @Override + public void draw() { + validate(); + + float x = this.x; + float y = this.y; + float scaleX = this.scaleX; + float scaleY = this.scaleY; + Draw.color(Color.white); + Draw.alpha(parentAlpha * color.a); + + TextureRegionDrawable region = new TextureRegionDrawable(getRegions(i)); + float rotation = getRotation(); + if(scaleX != 1 || scaleY != 1 || rotation != 0){ + region.draw(x + imageX, y + imageY, originX - imageX, originY - imageY, + imageWidth, imageHeight, scaleX, scaleY, rotation); + return; + } + region.draw(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); + + Draw.color(BarInfo.colors.get(i)); + if(ScissorStack.push(scissor.set(x, y, imageWidth * scaleX, imageHeight * scaleY * BarInfo.numbers.get(i)))){ + region.draw(x, y, imageWidth * scaleX, imageHeight * scaleY); + ScissorStack.pop(); + } + Draw.reset(); + } + }).size(iconMed * Scl.scl(modUiScale) * 0.75f); + })); + }}; + } + + + static class WeaponDisplay extends Table { + public WeaponDisplay() { + table().update(tt -> { + tt.clear(); + if(getTarget() instanceof Unit u && u.type != null && u.hasWeapons()) { + for(int r = 0; r < u.type.weapons.size; r++){ + Weapon weapon = u.type.weapons.get(r); + WeaponMount mount = u.mounts[r]; + int finalR = r; + tt.table(ttt -> { + ttt.left(); + if((1 + finalR) % 4 == 0) ttt.row(); + ttt.stack( + new Table(o -> { + o.left(); + o.add(new Image(!weapon.name.equals("") && weapon.outlineRegion.found() ? weapon.outlineRegion : u.type.uiIcon){ + @Override + public void draw(){ + validate(); + float x = this.x; + float y = this.y; + float scaleX = this.scaleX; + float scaleY = this.scaleY; + Draw.color(color); + Draw.alpha(parentAlpha * color.a); + + if(getDrawable() instanceof TransformDrawable){ + float rotation = getRotation(); + if(scaleX != 1 || scaleY != 1 || rotation != 0){ + getDrawable().draw(x + imageX, y + imageY, originX - imageX, originY - imageY, imageWidth, imageHeight, scaleX, scaleY, rotation); + return; + } + } + y -= (mount.reload) / weapon.reload * weapon.recoil; + if(getDrawable() != null) + getDrawable().draw(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); + } + }).size(Scl.scl(modUiScale) * iconLarge); + }), + new Table(h -> { + h.defaults().growX().height(Scl.scl(modUiScale) * 9f).width(Scl.scl(modUiScale) * iconLarge).padTop(Scl.scl(modUiScale) * 18f); + h.add(new SBar( + () -> "", + () -> Pal.accent.cpy().lerp(Color.orange, mount.reload / weapon.reload), + () -> mount.reload / weapon.reload).rect().init()); + h.pack(); + }) + ); + }).pad(4); + } + } + }); + } + } + static class UnitInfoDisplay extends Table { + public UnitInfoDisplay() { + table(table1 -> { + table1.left().top(); + + table1.table().update(t -> { + t.clear(); + if(getTarget() instanceof Unit u && u.item() != null) { + if(state.rules.damageExplosions) { + float power = u.item().charge * Mathf.pow(u.stack().amount, 1.11f) * 160f; + int powerAmount = (int)Mathf.clamp(power / 700, 0, 8); + int powerLength = 5 + Mathf.clamp((int)(Mathf.pow(power, 0.98f) / 500), 1, 18); + float powerDamage = 3 + Mathf.pow(power, 0.35f); + + if(powerAmount > 0) { + t.stack( + new Table(tt -> { + tt.image(Icon.power.getRegion()).size(8 * 3f * Scl.scl(modUiScale)); + }), + new Table(tt -> { + tt.right().top(); + Label label = new Label(()->powerAmount + ""); + label.setFontScale(0.75f * Scl.scl(modUiScale)); + tt.add(label).padBottom(4f).padLeft(4f); + tt.pack(); + }) + ).pad(4).visible(() -> state.rules.damageExplosions&&powerAmount > 0); + } + + if(u.item().flammability > 1) { + float flammability = u.item().flammability * u.stack().amount / 1.9f; + int fireAmount = (int)Mathf.clamp(flammability / 4, 0, 30); + t.stack( + new Table(tt -> { + tt.image(StatusEffects.burning.uiIcon).size(8 * 3f * Scl.scl(modUiScale)); + }), + new Table(tt -> { + tt.right().top(); + Label label = new Label(()->fireAmount+""); + label.setFontScale(0.75f * Scl.scl(modUiScale)); + tt.add(label).padBottom(4f).padLeft(4f); + tt.pack(); + }) + ).pad(4).visible(() -> state.rules.damageExplosions&&u.item().flammability > 1); + } + } + + float explosiveness = 2f + u.item().explosiveness * u.stack().amount * 1.53f; + float explosivenessMax = 2f + u.item().explosiveness * u.stack().amount * 1.53f; + int exploAmount = explosiveness <= 2 ? 0 : Mathf.clamp((int)(explosiveness / 11), 1, 25); + int exploAmountMax = explosivenessMax <= 2 ? 0 : Mathf.clamp((int)(explosivenessMax / 11), 1, 25); + float exploRadiusMin = Mathf.clamp(u.bounds() / 2f + explosiveness, 0, 50f) * (1f / exploAmount); + float exploRadiusMax = Mathf.clamp(u.bounds() / 2f + explosiveness, 0, 50f); + float exploDamage = explosiveness / 2f; + + if(exploAmount > 0){ + t.stack( + new Table(tt -> { + tt.image(Icon.modeAttack.getRegion()).size(8 * 3f * Scl.scl(modUiScale)); + }), + new Table(tt -> { + tt.right().top(); + Label label = new Label(()->""+ Strings.fixed(exploDamage * exploAmount, 1)); + label.setFontScale(0.75f * Scl.scl(modUiScale)); + label.setColor(Tmp.c1.set(Color.white).lerp(Pal.health, (exploAmount*1f)/exploAmountMax)); + tt.add(label).padBottom(4f).padLeft(8f); + tt.pack(); + }) + ).pad(4).visible(() -> exploAmount>0); + } + } + }).growX().visible(() -> getTarget() instanceof Unit); + table1.row(); + + float[] count = new float[]{-1}; + table1.table().update(t -> { + if(getTarget() instanceof Payloadc payload){ + if(count[0] != payload.payloadUsed()){ + t.clear(); + t.top().left(); + + float pad = 0; + float items = payload.payloads().size; + if(8 * 2 * items + pad * items > 275f){ + pad = (275f - (8 * 2) * items) / items; + } + int i = 0; + for(Payload p : payload.payloads()){ + t.image(p.icon()).size(8 * 2).padRight(pad); + if(++i % 12 == 0) t.row(); + } + + count[0] = payload.payloadUsed(); + } + }else{ + count[0] = -1; + t.clear(); + } + }).growX().visible(() -> getTarget() instanceof Payloadc p && p.payloadUsed() > 0).colspan(2); + table1.row(); + + Bits statuses = new Bits(); + table1.table().update(t -> { + t.left(); + if(getTarget() instanceof Statusc st){ + Bits applied = st.statusBits(); + if(!statuses.equals(applied)){ + t.clear(); + + if(applied != null){ + for(StatusEffect effect : content.statusEffects()){ + if(applied.get(effect.id) && !effect.isHidden()){ + t.image(effect.uiIcon).size(iconSmall).get().addListener(new Tooltip(l -> l.label(() -> + effect.localizedName + " [lightgray]" + UI.formatTime(st.getDuration(effect))).style(Styles.outlineLabel))); + } + } + statuses.set(applied); + } + } + } + }).left(); + }).get(); + } + } +} diff --git a/src/UnitInfo/ui/WaveDisplay.java b/src/UnitInfo/ui/WaveDisplay.java new file mode 100644 index 0000000..493e642 --- /dev/null +++ b/src/UnitInfo/ui/WaveDisplay.java @@ -0,0 +1,179 @@ +package UnitInfo.ui; + +import UnitInfo.SVars; +import arc.graphics.Color; +import arc.graphics.g2d.NinePatch; +import arc.input.KeyCode; +import arc.math.Mathf; +import arc.scene.Element; +import arc.scene.event.HandCursorListener; +import arc.scene.style.NinePatchDrawable; +import arc.scene.style.ScaledNinePatchDrawable; +import arc.scene.style.TextureRegionDrawable; +import arc.scene.ui.Image; +import arc.scene.ui.Label; +import arc.scene.ui.ScrollPane; +import arc.scene.ui.Tooltip; +import arc.scene.ui.layout.Scl; +import arc.scene.ui.layout.Table; +import arc.struct.ObjectIntMap; +import arc.struct.Seq; +import arc.util.Scaling; +import arc.util.Time; +import arc.util.Tmp; +import mindustry.content.StatusEffects; +import mindustry.game.SpawnGroup; +import mindustry.gen.Icon; +import mindustry.gen.Tex; +import mindustry.graphics.Pal; +import mindustry.ui.Fonts; +import mindustry.ui.Styles; + +import static UnitInfo.SVars.modUiScale; +import static arc.Core.*; +import static arc.Core.settings; +import static mindustry.Vars.*; + + +public class WaveDisplay extends Table { + static float waveScrollPos; + static Table table = new Table(); + + public WaveDisplay() { + fillParent = true; + visibility = () -> 1 == SVars.hud.uiIndex; + + defaults().size(Scl.scl(modUiScale) * 35 * 8f); + table(Tex.button, t -> { + ScrollPane pane = t.pane(Styles.nonePane, rebuild()).get(); + pane.update(() -> { + if (pane.hasScroll()) { + Element result = scene.hit(input.mouseX(), input.mouseY(), true); + if (result == null || !result.isDescendantOf(pane)) { + scene.setScrollFocus(null); + } + } + waveScrollPos = pane.getScrollY(); + }); + pane.setOverscroll(false, false); + pane.setScrollingDisabled(true, false); + pane.setScrollYForce(waveScrollPos); + + update(() -> { + NinePatchDrawable patch = (NinePatchDrawable) Tex.button; + t.setBackground(patch.tint(Tmp.c1.set(patch.getPatch().getColor()).a(settings.getInt("uiopacity") / 100f))); + }); + }).padRight(Scl.scl(modUiScale) * 70 * 8f); + } + + public Table rebuild(){ + table.clear(); + int winWave = state.isCampaign() && state.rules.winWave > 0 ? state.rules.winWave : Integer.MAX_VALUE; + for(int i = settings.getBool("pastwave") ? 0 : state.wave - 1; i <= Math.min(state.wave + settings.getInt("wavemax"), winWave - 2); i++){ + final int j = i; + if(!settings.getBool("emptywave") && state.rules.spawns.find(g -> g.getSpawned(j) > 0) == null) continue; + table.table(table1 -> { + table1.stack( + new Table(t -> { + Label label = new Label(() -> "[#" + (state.wave == j ? Color.red.toString() : Pal.accent.toString()) + "]" + j + "[]"); + label.setFontScale(Scl.scl(modUiScale)); + t.add(label).padRight(Scl.scl(modUiScale) * 24 * 8f); + }), + new Table(Tex.underline, t -> { + t.marginLeft(Scl.scl(modUiScale) * 3 * 8f); + if(settings.getBool("emptywave") && state.rules.spawns.find(g -> g.getSpawned(j) > 0) == null) { + t.center(); + Label label = new Label("[lightgray][]"); + label.setFontScale(Scl.scl(modUiScale)); + t.add(label); + return; + } + + ObjectIntMap groups = new ObjectIntMap<>(); + for(SpawnGroup group : state.rules.spawns) { + if(group.getSpawned(j) <= 0) continue; + SpawnGroup sameTypeKey = groups.keys().toArray().find(g -> g.type == group.type && g.effect != StatusEffects.boss); + if(sameTypeKey != null) groups.increment(sameTypeKey, sameTypeKey.getSpawned(j)); + else groups.put(group, group.getSpawned(j)); + } + Seq groupSorted = groups.keys().toArray().copy().sort((g1, g2) -> { + int boss = Boolean.compare(g1.effect != StatusEffects.boss, g2.effect != StatusEffects.boss); + if(boss != 0) return boss; + int hitSize = Float.compare(-g1.type.hitSize, -g2.type.hitSize); + if(hitSize != 0) return hitSize; + return Integer.compare(-g1.type.id, -g2.type.id); + }); + ObjectIntMap groupsTmp = new ObjectIntMap<>(); + groupSorted.each(g -> groupsTmp.put(g, groups.get(g))); + + int row = 0; + for(SpawnGroup group : groupsTmp.keys()){ + int spawners = state.rules.waveTeam.cores().size + (group.type.flying ? spawner.countFlyerSpawns() : spawner.countGroundSpawns()); + int amount = groupsTmp.get(group); + t.table(tt -> { + Image image = new Image(group.type.uiIcon).setScaling(Scaling.fit); + tt.stack( + new Table(ttt -> { + ttt.center(); + ttt.add(image).size(iconMed * Scl.scl(modUiScale)); + ttt.pack(); + }), + + new Table(ttt -> { + ttt.bottom().left(); + Label label = new Label(() -> amount + ""); + label.setFontScale(Scl.scl(modUiScale) * 0.9f); + Label multi = new Label(() -> "[gray]x" + spawners); + multi.setFontScale(Scl.scl(modUiScale) * 0.7f); + ttt.add(label).padTop(2f); + ttt.add(multi).padTop(10f); + ttt.pack(); + }), + + new Table(ttt -> { + ttt.top().right(); + Image image1 = new Image(Icon.warning.getRegion()).setScaling(Scaling.fit); + image1.update(() -> { + image1.setColor(Tmp.c2.set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time, 2f, 1f))); + }); + ttt.add(image1).size(Scl.scl(modUiScale) * 12f); + ttt.visible(() -> group.effect == StatusEffects.boss); + ttt.pack(); + }) + ).pad(2f * Scl.scl(modUiScale)); + tt.clicked(() -> { + if(input.keyDown(KeyCode.shiftLeft) && Fonts.getUnicode(group.type.name) != 0){ + app.setClipboardText((char)Fonts.getUnicode(group.type.name) + ""); + ui.showInfoFade("@copied"); + }else{ + ui.content.show(group.type); + } + }); + if(!mobile){ + HandCursorListener listener = new HandCursorListener(); + tt.addListener(listener); + tt.update(() -> { + image.color.lerp(!listener.isOver() ? Color.lightGray : Color.white, Mathf.clamp(0.4f * Time.delta)); + }); + } + tt.addListener(new Tooltip(ttt -> ttt.table(Styles.black6, to -> { + to.margin(4f).left(); + to.add("[stat]" + group.type.localizedName + "[]").row(); + to.row(); + to.add(bundle.format("shar-stat-waveAmount", amount + " [lightgray]x" + spawners + "[]")).row(); + to.add(bundle.format("shar-stat-waveShield", group.getShield(j))).row(); + if(group.effect != null && group.effect != StatusEffects.none) + to.add(bundle.get("shar-stat.waveStatus") + group.effect.emoji() + "[stat]" + group.effect.localizedName).row(); + }))); + }); + if(++row % 4 == 0) t.row(); + } + }) + ); + }); + table.row(); + } + + return table; + } +}