package UnitInfo.core; import UnitInfo.ui.*; import arc.*; 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.entities.Units; import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.input.*; import mindustry.logic.Ranged; import mindustry.type.*; import mindustry.ui.*; 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(); float waveScrollPos; float itemScrollPos; float weaponScrollPos; Teamc shotTarget; Teamc lockedTarget; ImageButton lockButton; boolean locked = false; boolean waveShown; float a; int uiIndex = 0; //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(); @SuppressWarnings("unchecked") public T getTarget(){ if(locked && lockedTarget != null) { if(settings.getBool("deadTarget") && !Groups.all.contains(e -> e == lockedTarget)) { lockedTarget = null; locked = false; } 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. else if(getTile() != null && getTile().build != null) return (T) getTile().build; //if there isn't unit but there is build, return it. else if(player.unit() instanceof BlockUnitUnit b && b.tile() != null) return (T)b.tile(); return (T) player.unit(); //if there aren't unit and not build, return player. } public @Nullable Tile getTile(){ return Vars.world.tileWorld(input.mouseWorldX(), input.mouseWorldY()); } public void setEvents() { Events.run(EventType.Trigger.update, ()->{ OverDrawer.target = getTarget(); OverDrawer.locked = locked; if(settings.getBool("deadTarget") && locked && lockedTarget != null && !Groups.all.contains(e -> e == lockedTarget)) { lockedTarget = null; locked = false; } if(Scl.scl(modUiScale) != settings.getInt("infoUiScale") / 100f){ modUiScale = settings.getInt("infoUiScale") / 100f; mainTable.clearChildren(); addTable(); coreItems.rebuild(); } if((input.keyDown(KeyCode.shiftRight) || input.keyDown(KeyCode.shiftLeft))){ if(input.keyTap(KeyCode.r)) lockButton.change(); } if(settings.getBool("autoShooting")) { Unit unit = player.unit(); if (unit.type == null) return; boolean omni = unit.type.omniMovement; boolean validHealTarget = unit.type.canHeal && shotTarget instanceof Building b && b.isValid() && b.damaged() && shotTarget.team() == unit.team && shotTarget.within(unit, unit.type.range); boolean boosted = (unit instanceof Mechc && unit.isFlying()); if ((unit.type != null && Units.invalidateTarget(shotTarget, unit, unit.type.range) && !validHealTarget) || state.isEditor()) { shotTarget = null; } float mouseAngle = unit.angleTo(unit.aimX(), unit.aimY()); boolean aimCursor = omni && player.shooting && unit.type.hasWeapons() && unit.type.faceTarget && !boosted && unit.type.rotateShooting; unit.lookAt(aimCursor ? mouseAngle : unit.prefRotation()); //update shooting if not building + not mining if(!player.unit().activelyBuilding() && player.unit().mineTile == null) { if(input.keyDown(KeyCode.mouseLeft)) { player.shooting = !boosted; unit.aim(player.mouseX = input.mouseWorldX(), player.mouseY = input.mouseWorldY()); } else if(shotTarget == null) { player.shooting = false; if(unit instanceof BlockUnitUnit b) { if(b.tile() instanceof ControlBlock c && !c.shouldAutoTarget()) { Building build = b.tile(); float range = build instanceof Ranged ? ((Ranged) build).range() : 0f; boolean targetGround = build instanceof Turret.TurretBuild && ((Turret) build.block).targetAir; boolean targetAir = build instanceof Turret.TurretBuild && ((Turret) build.block).targetGround; shotTarget = Units.closestTarget(build.team, build.x, build.y, range, u -> u.checkTarget(targetAir, targetGround), u -> targetGround); } else shotTarget = null; } else if(unit.type != null) { float range = unit.hasWeapons() ? unit.range() : 0f; shotTarget = Units.closestTarget(unit.team, unit.x, unit.y, range, u -> u.checkTarget(unit.type.targetAir, unit.type.targetGround), u -> unit.type.targetGround); if(unit.type.canHeal && shotTarget == null) { shotTarget = Geometry.findClosest(unit.x, unit.y, indexer.getDamaged(Team.sharded)); if (shotTarget != null && !unit.within(shotTarget, range)) { shotTarget = null; } } } } else { player.shooting = !boosted; unit.rotation(Angles.angle(unit.x, unit.y, shotTarget.x(), shotTarget.y())); unit.aim(shotTarget.x(), shotTarget.y()); } } unit.controlWeapons(player.shooting && !boosted); } }); Events.on(EventType.BlockDestroyEvent.class, e -> { if(e.tile.block() instanceof CoreBlock) coreItems.resetUsed(); }); Events.on(EventType.CoreChangeEvent.class, e -> coreItems.resetUsed()); Events.on(EventType.ResetEvent.class, e -> coreItems.resetUsed()); } public void setLeftUnitTable(Table table) { table.table(t -> { t.center(); int[] i = {0}; enemyamount = Groups.unit.count(u -> u.team == state.rules.waveTeam); content.units().each(type -> Groups.unit.contains(u -> u.type == type && u.team == state.rules.waveTeam && u.isBoss()), type -> { t.table(tt -> { tt.add(new Stack() {{ add(new Table(ttt -> { ttt.image(type.uiIcon).size(iconSmall); })); add(new Table(ttt -> { ttt.right().bottom(); Label label = new Label(() -> Groups.unit.count(u -> u.type == type && u.team == state.rules.waveTeam && u.isBoss()) + ""); label.setFontScale(0.75f); ttt.add(label); ttt.pack(); })); add(new Table(ttt -> { ttt.top().right(); Image image = new Image(Icon.warning.getRegion()).setScaling(Scaling.fit); image.update(() -> image.setColor(Tmp.c2.set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time, 2f, 1f)))); ttt.add(image).size(Scl.scl(modUiScale) * 12f); ttt.pack(); })); }}).pad(6); }); if(++i[0] % 6 == 0) t.row(); }); t.row(); i[0] = 0; content.units().each(type -> Groups.unit.contains(u -> u.type == type && u.team == state.rules.waveTeam && !u.isBoss()), type -> { t.table(tt -> { tt.add(new Stack() {{ add(new Table(ttt -> { ttt.add(new Image(type.uiIcon)).size(iconSmall); })); add(new Table(ttt -> { ttt.right().bottom(); Label label = new Label(() -> Groups.unit.count(u -> u.type == type && u.team == state.rules.waveTeam && !u.isBoss()) + ""); label.setFontScale(0.75f); ttt.add(label); ttt.pack(); })); }}).pad(6); }); if(++i[0] % 6 == 0) t.row(); }); }); } public void setTile(Table table){ table.table(t -> { t.table(Tex.underline2, head -> { head.table(image -> { image.left(); image.image(() -> getTile() == null ? clear : getTile().floor().uiIcon == error ? clear : getTile().floor().uiIcon).size(iconSmall); image.image(() -> getTile() == null ? clear : getTile().overlay().uiIcon == error ? clear : getTile().overlay().uiIcon).size(iconSmall); image.image(() -> getTile() == null ? clear : getTile().block().uiIcon == error ? clear : getTile().block().uiIcon).size(iconSmall); }); Label label = new Label(() -> getTile() == null ? "(null, null)" : "(" + getTile().x + ", " + getTile().y + ")"); head.add(label).center(); }); }); } public void addWaveInfoTable() { waveInfoTable = new Table(Tex.buttonEdge4, t -> { t.defaults().width(34 * 8f).center(); t.table().update(tt -> { tt.clear(); setTile(tt); tt.row(); setLeftUnitTable(tt); }); }); Table pathlineTable = new Table(t -> { t.right(); Button pathBtn = new ImageButton(new ScaledNinePatchDrawable(new NinePatch(Icon.grid.getRegion()), 0.5f), Styles.clearToggleTransi); Button unitBtn = new ImageButton(new ScaledNinePatchDrawable(new NinePatch(Icon.grid.getRegion()), 0.5f), Styles.clearToggleTransi); Button logicBtn = new ImageButton(new ScaledNinePatchDrawable(new NinePatch(Icon.grid.getRegion()), 0.5f), Styles.clearToggleTransi); pathBtn.addListener(new Tooltip(l -> l.label(() -> "PathLine " + (pathLine ? "[accent]Enabled[]" : "[gray]Disabled[]")))); pathBtn.clicked(() -> { pathLine = !pathLine; pathBtn.setChecked(pathLine); }); unitBtn.addListener(new Tooltip(l -> l.label(() -> "UnitLine " + (unitLine ? "[accent]Enabled[]" : "[gray]Disabled[]")))); unitBtn.clicked(() -> { unitLine = !unitLine; unitBtn.setChecked(unitLine); }); logicBtn.addListener(new Tooltip(l -> l.label(() -> "LogicLine " + (logicLine ? "[accent]Enabled[]" : "[gray]Disabled[]")))); logicBtn.clicked(() -> { logicLine = !logicLine; logicBtn.setChecked(logicLine); }); t.add(pathBtn).padLeft(4 * 8f).size(3 * 8f).row(); t.add(unitBtn).padLeft(4 * 8f).size(3 * 8f).row(); t.add(logicBtn).padLeft(4 * 8f).size(3 * 8f).row(); }); Table waveTable = (Table) scene.find("waves"); Table table = (Table)waveTable.getChildren().first(); //HudFragment#198, name: x Table statusTable = Version.number >= 131 ? (Table)scene.find("statustable") : (Table)waveTable.getChildren().get(1); waveTable.removeChild(statusTable); table.row(); table.stack( new Table(tt -> tt.collapser(t -> t.stack(waveInfoTable, statusTable.top(), pathlineTable), true, () -> waveShown)).top(), new Table(tt -> tt.button(Icon.downOpen, Styles.clearToggleTransi, () -> waveShown = !waveShown).size(4 * 8f).checked(b -> { b.getImage().setDrawable(waveShown ? Icon.upOpen : Icon.downOpen); return waveShown; })).left().top()).visible(() -> settings.getBool("waveui")); } public void reset(int index, Seq