added OverDrawer.java

This commit is contained in:
sharlotte
2021-08-26 13:47:55 +09:00
parent 0c76cd3ec8
commit 698f53b49d
3 changed files with 285 additions and 243 deletions

View File

@@ -17,6 +17,7 @@ import arc.scene.utils.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.*; import mindustry.*;
import mindustry.ai.Astar;
import mindustry.content.*; import mindustry.content.*;
import mindustry.core.*; import mindustry.core.*;
import mindustry.entities.*; import mindustry.entities.*;
@@ -26,6 +27,7 @@ import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.logic.*; import mindustry.logic.*;
import mindustry.maps.SectorDamage;
import mindustry.type.*; import mindustry.type.*;
import mindustry.type.ammo.*; import mindustry.type.ammo.*;
import mindustry.ui.*; import mindustry.ui.*;
@@ -45,6 +47,7 @@ import mindustry.world.blocks.production.AttributeCrafter;
import mindustry.world.blocks.production.Drill; import mindustry.world.blocks.production.Drill;
import mindustry.world.blocks.production.GenericCrafter; import mindustry.world.blocks.production.GenericCrafter;
import mindustry.world.blocks.production.SolidPump; import mindustry.world.blocks.production.SolidPump;
import mindustry.world.blocks.storage.CoreBlock;
import mindustry.world.blocks.units.Reconstructor; import mindustry.world.blocks.units.Reconstructor;
import mindustry.world.blocks.units.UnitFactory; import mindustry.world.blocks.units.UnitFactory;
@@ -81,11 +84,6 @@ public class HudUi {
Seq<Color> colors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); Seq<Color> colors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear);
Seq<Color> lastColors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear); Seq<Color> lastColors = Seq.with(Color.clear,Color.clear,Color.clear,Color.clear,Color.clear,Color.clear);
CoresItemsDisplay coreItems = new CoresItemsDisplay(Team.baseTeams); CoresItemsDisplay coreItems = new CoresItemsDisplay(Team.baseTeams);
@Nullable Teamc target;
public Seq<MassDriver.MassDriverBuild> linkedMasses = new Seq<>();
public Seq<PayloadMassDriver.PayloadDriverBuild> linkedPayloadMasses = new Seq<>();
public Seq<Building> linkedNodes = new Seq<>();
public final Rect scissor = new Rect(); public final Rect scissor = new Rect();
@@ -114,231 +112,24 @@ public class HudUi {
return Vars.world.tileWorld(input.mouseWorldX(), input.mouseWorldY()); return Vars.world.tileWorld(input.mouseWorldX(), input.mouseWorldY());
} }
public void drawMassPayloadLink(PayloadMassDriver.PayloadDriverBuild from){ public void setEvents() {
Groups.build.each(b -> b instanceof PayloadMassDriver.PayloadDriverBuild fromMass &&
world.build(fromMass.link) == from &&
from.within(fromMass.x, fromMass.y, ((PayloadMassDriver)fromMass.block).range) &&
!linkedPayloadMasses.contains(from), b -> {
linkedPayloadMasses.add((PayloadMassDriver.PayloadDriverBuild) b);
drawMassPayloadLink((PayloadMassDriver.PayloadDriverBuild) b);
});
if(world.build(from.link) instanceof PayloadMassDriver.PayloadDriverBuild to && from != to && Events.run(EventType.Trigger.update, ()->{
to.within(from.x, from.y, ((PayloadMassDriver)from.block).range)){
float sin = Mathf.absin(Time.time, 6f, 1f);
Tmp.v1.set(from.x + from.block.offset, from.y + from.block.offset).sub(to.x, to.y).limit(from.block.size * tilesize + sin + 0.5f);
float x2 = from.x - Tmp.v1.x, y2 = from.y - Tmp.v1.y,
x1 = to.x + Tmp.v1.x, y1 = to.y + Tmp.v1.y;
int segs = (int)(to.dst(from.x, from.y)/tilesize);
Lines.stroke(4f, Pal.gray);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(2f, Pal.placing);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(1f, Pal.accent);
Drawf.circles(from.x, from.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f, Pal.accent);
for(var shooter : from.waitingShooters){
Drawf.circles(shooter.x, shooter.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(shooter.x, shooter.y, from.x, from.y, from.block.size * tilesize + sin, 4f + sin);
}
if(from.link != -1 && world.build(from.link) instanceof PayloadMassDriver.PayloadDriverBuild other && other.block == from.block && other.team == from.team && from.within(other, ((PayloadMassDriver)from.block).range)){
Building target = world.build(from.link);
Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(from.x, from.y, target.x, target.y, from.block.size * tilesize + sin, 4f + sin);
}
if(world.build(to.link) instanceof PayloadMassDriver.PayloadDriverBuild newTo && to != newTo &&
newTo.within(to.x, to.y, ((PayloadMassDriver)to.block).range) && !linkedPayloadMasses.contains(to)){
linkedPayloadMasses.add(to);
drawMassPayloadLink(to);
}
}
}
public void drawMassLink(MassDriver.MassDriverBuild from){
Groups.build.each(b -> b instanceof MassDriver.MassDriverBuild fromMass &&
world.build(fromMass.link) == from &&
from.within(fromMass.x, fromMass.y, ((MassDriver)fromMass.block).range) &&
!linkedMasses.contains(from), b -> {
linkedMasses.add((MassDriver.MassDriverBuild) b);
drawMassLink((MassDriver.MassDriverBuild) b);
});
if(world.build(from.link) instanceof MassDriver.MassDriverBuild to && from != to && to.within(from.x, from.y, ((MassDriver)from.block).range)){
float sin = Mathf.absin(Time.time, 6f, 1f);
Tmp.v1.set(from.x + from.block.offset, from.y + from.block.offset).sub(to.x, to.y).limit(from.block.size * tilesize + sin + 0.5f);
float x2 = from.x - Tmp.v1.x, y2 = from.y - Tmp.v1.y,
x1 = to.x + Tmp.v1.x, y1 = to.y + Tmp.v1.y;
int segs = (int)(to.dst(from.x, from.y)/tilesize);
Lines.stroke(4f, Pal.gray);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(2f, Pal.placing);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(1f, Pal.accent);
Drawf.circles(from.x, from.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f, Pal.accent);
for(var shooter : from.waitingShooters){
Drawf.circles(shooter.x, shooter.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(shooter.x, shooter.y, from.x, from.y, from.block.size * tilesize + sin, 4f + sin);
}
if(from.link != -1 && world.build(from.link) instanceof MassDriver.MassDriverBuild other && other.block == from.block && other.team == from.team && from.within(other, ((MassDriver)from.block).range)){
Building target = world.build(from.link);
Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(from.x, from.y, target.x, target.y, from.block.size * tilesize + sin, 4f + sin);
}
if(world.build(to.link) instanceof MassDriver.MassDriverBuild newTo && to != newTo &&
newTo.within(to.x, to.y, ((MassDriver)to.block).range) && !linkedMasses.contains(to)){
linkedMasses.add(to);
drawMassLink(to);
}
}
}
public Seq<Building> getPowerLinkedBuilds(Building build) {
Seq<Building> linkedBuilds = new Seq<>();
build.power.links.each(i -> linkedBuilds.add(world.build(i)));
build.proximity().each(linkedBuilds::add);
linkedBuilds.filter(b -> b != null && b.power != null);
if(!build.block.outputsPower && !(build instanceof PowerNode.PowerNodeBuild))
linkedBuilds.filter(b -> b.block.outputsPower || b instanceof PowerNode.PowerNodeBuild);
return linkedBuilds;
}
public void drawNodeLink(Building node) {
if(node.power == null) return;
if(!linkedNodes.contains(node)) {
linkedNodes.add(node);
getPowerLinkedBuilds(node).each(other -> {
float angle1 = Angles.angle(node.x, node.y, other.x, other.y),
vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1),
len1 = node.block.size * tilesize / 2f - 1.5f, len2 = other.block.size * tilesize / 2f - 1.5f;
Draw.color(Color.white, Color.valueOf("98ff98"), (1f - node.power.graph.getSatisfaction()) * 0.86f + Mathf.absin(3f, 0.1f));
Draw.alpha(Renderer.laserOpacity);
Drawf.laser(node.team, atlas.find("unitinfo-Slaser"), atlas.find("unitinfo-Slaser-end"), node.x + vx*len1, node.y + vy*len1, other.x - vx*len2, other.y - vy*len2, 0.25f);
if(other.power != null) getPowerLinkedBuilds(other).each(this::drawNodeLink);
});
}
}
public void setEvent(){
Events.run(EventType.Trigger.draw, () -> {
if(settings.getBool("deadTarget") && locked && lockedTarget != null && !Groups.all.contains(e -> e == lockedTarget)) { if(settings.getBool("deadTarget") && locked && lockedTarget != null && !Groups.all.contains(e -> e == lockedTarget)) {
lockedTarget = null; lockedTarget = null;
locked = false; locked = false;
} }
if(settings.getBool("linkedMass")){
if(getTarget() instanceof MassDriver.MassDriverBuild mass) {
linkedMasses.clear();
drawMassLink(mass);
}
else if(getTarget() instanceof PayloadMassDriver.PayloadDriverBuild mass) {
linkedPayloadMasses.clear();
drawMassPayloadLink(mass);
}
}
if(settings.getBool("linkedNode") && getTarget() instanceof Building node){
linkedNodes.clear();
drawNodeLink(node);
}
if(settings.getBool("select") && getTarget() != null) {
Posc entity = getTarget();
for(int i = 0; i < 4; i++){
float rot = i * 90f + 45f + (-Time.time) % 360f;
float length = (entity instanceof Unit ? ((Unit)entity).hitSize : entity instanceof Building ? ((Building)entity).block.size * tilesize : 0) * 1.5f + 2.5f;
Draw.color(Tmp.c1.set(locked ? Color.orange : Color.darkGray).lerp(locked ? Color.scarlet : Color.gray, Mathf.absin(Time.time, 2f, 1f)).a(settings.getInt("selectopacity") / 100f));
Draw.rect("select-arrow", entity.x() + Angles.trnsx(rot, length), entity.y() + Angles.trnsy(rot, length), length / 1.9f, length / 1.9f, rot - 135f);
}
if(settings.getBool("distanceLine") && player.unit() != null && !player.unit().dead && getTarget() != player.unit()) { //need selected other unit with living player
Teamc from = player.unit();
Teamc to = getTarget();
float sin = Mathf.absin(Time.time, 6f, 1f);
if(player.unit() instanceof BlockUnitUnit bu) Tmp.v1.set(bu.x() + bu.tile().block.offset, bu.y() + bu.tile().block.offset).sub(to.x(), to.y()).limit(bu.tile().block.size * tilesize + sin + 0.5f);
else Tmp.v1.set(from.x(), from.y()).sub(to.x(), to.y()).limit(player.unit().hitSize + sin + 0.5f);
float x2 = from.x() - Tmp.v1.x, y2 = from.y() - Tmp.v1.y,
x1 = to.x() + Tmp.v1.x, y1 = to.y() + Tmp.v1.y;
int segs = (int) (to.dst(from.x(), from.y()) / tilesize);
Lines.stroke(2.5f, Pal.gray);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(1f, Pal.placing);
Lines.dashLine(x1, y1, x2, y2, segs);
Fonts.outline.draw(Strings.fixed(to.dst(from.x(), from.y()), 2) + " (" + segs + "tiles)",
from.x() + Angles.trnsx(Angles.angle(from.x(), from.y(), to.x(), to.y()), player.unit().hitSize() + 40),
from.y() + Angles.trnsy(Angles.angle(from.x(), from.y(), to.x(), to.y()), player.unit().hitSize() + 40) - 3,
Pal.accent, 0.25f, false, Align.center);
}
}
Draw.reset();
});
Events.run(EventType.Trigger.update, ()->{
if(Scl.scl(modUiScale) != settings.getInt("infoUiScale") / 100f){ if(Scl.scl(modUiScale) != settings.getInt("infoUiScale") / 100f){
modUiScale = settings.getInt("infoUiScale") / 100f; modUiScale = settings.getInt("infoUiScale") / 100f;
mainTable.clearChildren(); mainTable.clearChildren();
addTable(); addTable();
coreItems.rebuild(); coreItems.rebuild();
} }
if((input.keyDown(KeyCode.shiftRight) || input.keyDown(KeyCode.shiftLeft))){ if((input.keyDown(KeyCode.shiftRight) || input.keyDown(KeyCode.shiftLeft))){
if(input.keyTap(KeyCode.r)) lockButton.change(); 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 && target instanceof Building && ((Building) target).isValid() && target.team() == unit.team && ((Building) target).damaged() && target.within(unit, unit.type.range);
boolean boosted = (unit instanceof Mechc && unit.isFlying());
if ((unit.type != null && Units.invalidateTarget(target, unit, unit.type.range) && !validHealTarget) || state.isEditor()) {
target = 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(target == 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;
target = Units.closestTarget(build.team, build.x, build.y, range, u -> u.checkTarget(targetAir, targetGround), u -> targetGround);
}
else target = null;
} else if(unit.type != null) {
float range = unit.hasWeapons() ? unit.range() : 0f;
target = 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 && target == null) {
target = Geometry.findClosest(unit.x, unit.y, indexer.getDamaged(Team.sharded));
if (target != null && !unit.within(target, range)) {
target = null;
}
}
}
} else {
player.shooting = !boosted;
unit.rotation(Angles.angle(unit.x, unit.y, target.x(), target.y()));
unit.aim(target.x(), target.y());
}
}
unit.controlWeapons(player.shooting && !boosted);
}
}); });
Events.on(EventType.BlockDestroyEvent.class, e -> coreItems.resetUsed()); Events.on(EventType.BlockDestroyEvent.class, e -> coreItems.resetUsed());
@@ -346,20 +137,6 @@ public class HudUi {
Events.on(EventType.ResetEvent.class, e -> coreItems.resetUsed()); Events.on(EventType.ResetEvent.class, e -> coreItems.resetUsed());
} }
public void reset(int index, Seq<Button> buttons, Label label, Table table, Table labelTable, String hud){
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);
baseTable = table.table(tt -> tt.stack(unitTable, waveTable, itemTable, labelTable).align(Align.left).left().visible(() -> settings.getBool("infoui"))).get();
a = 1f;
}
public void setLeftUnitTable(Table table) { public void setLeftUnitTable(Table table) {
table.table(t -> { table.table(t -> {
t.center(); t.center();
@@ -429,18 +206,14 @@ public class HudUi {
public void addWaveInfoTable() { public void addWaveInfoTable() {
waveInfoTable = new Table(Tex.buttonEdge4, t -> { waveInfoTable = new Table(Tex.buttonEdge4, t -> {
t.defaults().width(34 * 8f).center(); t.defaults().width(34 * 8f).center();
setTile(t); t.table().update(tt -> {
t.row(); tt.clear();
setLeftUnitTable(t); setTile(tt);
t.update(() -> { tt.row();
if(enemyamount != Groups.unit.count(u -> u.team == state.rules.waveTeam)) { setLeftUnitTable(tt);
t.clearChildren();
setTile(t);
t.row();
setLeftUnitTable(t);
}
}); });
}); });
Table pathlineTable = new Table(t -> { Table pathlineTable = new Table(t -> {
t.right(); t.right();
@@ -478,8 +251,22 @@ public class HudUi {
Table statusTable = (Table) waveTable.getChildren().get(1); Table statusTable = (Table) waveTable.getChildren().get(1);
waveTable.removeChild(statusTable); waveTable.removeChild(statusTable);
table.row(); table.row();
statusTable.top();
table.stack(waveInfoTable, statusTable, pathlineTable); table.stack(waveInfoTable, statusTable.top(), pathlineTable);
}
public void reset(int index, Seq<Button> buttons, Label label, Table table, Table labelTable, String hud){
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);
baseTable = table.table(tt -> tt.stack(unitTable, waveTable, itemTable, labelTable).align(Align.left).left().visible(() -> settings.getBool("infoui"))).get();
a = 1f;
} }
public void addTable(){ public void addTable(){
@@ -560,7 +347,7 @@ public class HudUi {
if(target instanceof Unit unit && unit.type != null || if(target instanceof Unit unit && unit.type != null ||
target instanceof UnitFactory.UnitFactoryBuild || target instanceof UnitFactory.UnitFactoryBuild ||
target instanceof Reconstructor.ReconstructorBuild){ target instanceof Reconstructor.ReconstructorBuild){
region = Icon.units.getRegion(); //region = SIcons.unit;
} else if(target instanceof AttributeCrafter.AttributeCrafterBuild || } else if(target instanceof AttributeCrafter.AttributeCrafterBuild ||
target instanceof SolidPump.SolidPumpBuild || target instanceof SolidPump.SolidPumpBuild ||
target instanceof ThermalGenerator.ThermalGeneratorBuild){ target instanceof ThermalGenerator.ThermalGeneratorBuild){

View File

@@ -60,7 +60,8 @@ public class Main extends Mod {
hud.addUnitTable(); hud.addUnitTable();
hud.addTable(); hud.addTable();
hud.addWaveInfoTable(); hud.addWaveInfoTable();
hud.setEvent(); hud.setEvents();
OverDrawer.setEvent();
}); });
Events.on(WorldLoadEvent.class, e -> { Events.on(WorldLoadEvent.class, e -> {

View File

@@ -0,0 +1,254 @@
package UnitInfo.core;
import arc.*;
import arc.graphics.Color;
import arc.graphics.g2d.*;
import arc.input.KeyCode;
import arc.math.*;
import arc.math.geom.Geometry;
import arc.struct.Seq;
import arc.util.*;
import mindustry.core.Renderer;
import mindustry.entities.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.logic.Ranged;
import mindustry.ui.Fonts;
import mindustry.world.blocks.ControlBlock;
import mindustry.world.blocks.defense.turrets.Turret;
import mindustry.world.blocks.distribution.MassDriver;
import mindustry.world.blocks.payloads.PayloadMassDriver;
import mindustry.world.blocks.power.PowerNode;
import static UnitInfo.SVars.hud;
import static arc.Core.*;
import static arc.Core.input;
import static mindustry.Vars.*;
import static mindustry.Vars.player;
public class OverDrawer {
@Nullable public static Teamc target;
public static Seq<MassDriver.MassDriverBuild> linkedMasses = new Seq<>();
public static Seq<PayloadMassDriver.PayloadDriverBuild> linkedPayloadMasses = new Seq<>();
public static Seq<Building> linkedNodes = new Seq<>();
@SuppressWarnings("unchecked")
public static <T extends Teamc> T getTarget(){
return (T) (target = hud.getTarget());
}
public static void setEvent(){
Events.run(EventType.Trigger.draw, () -> {
if(settings.getBool("linkedMass")){
if(getTarget() instanceof MassDriver.MassDriverBuild mass) {
linkedMasses.clear();
drawMassLink(mass);
}
else if(getTarget() instanceof PayloadMassDriver.PayloadDriverBuild mass) {
linkedPayloadMasses.clear();
drawMassPayloadLink(mass);
}
}
if(settings.getBool("linkedNode") && getTarget() instanceof Building node){
linkedNodes.clear();
drawNodeLink(node);
}
if(settings.getBool("select") && getTarget() != null) {
Posc entity = getTarget();
for(int i = 0; i < 4; i++){
float rot = i * 90f + 45f + (-Time.time) % 360f;
float length = (entity instanceof Unit ? ((Unit)entity).hitSize : entity instanceof Building ? ((Building)entity).block.size * tilesize : 0) * 1.5f + 2.5f;
Draw.color(Tmp.c1.set(hud.locked ? Color.orange : Color.darkGray).lerp(hud.locked ? Color.scarlet : Color.gray, Mathf.absin(Time.time, 2f, 1f)).a(settings.getInt("selectopacity") / 100f));
Draw.rect("select-arrow", entity.x() + Angles.trnsx(rot, length), entity.y() + Angles.trnsy(rot, length), length / 1.9f, length / 1.9f, rot - 135f);
}
if(settings.getBool("distanceLine") && player.unit() != null && !player.unit().dead && getTarget() != player.unit()) { //need selected other unit with living player
Teamc from = player.unit();
Teamc to = getTarget();
float sin = Mathf.absin(Time.time, 6f, 1f);
if(player.unit() instanceof BlockUnitUnit bu) Tmp.v1.set(bu.x() + bu.tile().block.offset, bu.y() + bu.tile().block.offset).sub(to.x(), to.y()).limit(bu.tile().block.size * tilesize + sin + 0.5f);
else Tmp.v1.set(from.x(), from.y()).sub(to.x(), to.y()).limit(player.unit().hitSize + sin + 0.5f);
float x2 = from.x() - Tmp.v1.x, y2 = from.y() - Tmp.v1.y,
x1 = to.x() + Tmp.v1.x, y1 = to.y() + Tmp.v1.y;
int segs = (int) (to.dst(from.x(), from.y()) / tilesize);
Lines.stroke(2.5f, Pal.gray);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(1f, Pal.placing);
Lines.dashLine(x1, y1, x2, y2, segs);
Fonts.outline.draw(Strings.fixed(to.dst(from.x(), from.y()), 2) + " (" + segs + "tiles)",
from.x() + Angles.trnsx(Angles.angle(from.x(), from.y(), to.x(), to.y()), player.unit().hitSize() + 40),
from.y() + Angles.trnsy(Angles.angle(from.x(), from.y(), to.x(), to.y()), player.unit().hitSize() + 40) - 3,
Pal.accent, 0.25f, false, Align.center);
}
}
Draw.reset();
});
Events.run(EventType.Trigger.update, ()->{
if(settings.getBool("autoShooting")) {
Unit unit = player.unit();
if (unit.type == null) return;
boolean omni = unit.type.omniMovement;
boolean validHealTarget = unit.type.canHeal && target instanceof Building && ((Building) target).isValid() && target.team() == unit.team && ((Building) target).damaged() && target.within(unit, unit.type.range);
boolean boosted = (unit instanceof Mechc && unit.isFlying());
if ((unit.type != null && Units.invalidateTarget(target, unit, unit.type.range) && !validHealTarget) || state.isEditor()) {
target = 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(target == 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;
target = Units.closestTarget(build.team, build.x, build.y, range, u -> u.checkTarget(targetAir, targetGround), u -> targetGround);
}
else target = null;
} else if(unit.type != null) {
float range = unit.hasWeapons() ? unit.range() : 0f;
target = 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 && target == null) {
target = Geometry.findClosest(unit.x, unit.y, indexer.getDamaged(Team.sharded));
if (target != null && !unit.within(target, range)) {
target = null;
}
}
}
} else {
player.shooting = !boosted;
unit.rotation(Angles.angle(unit.x, unit.y, target.x(), target.y()));
unit.aim(target.x(), target.y());
}
}
unit.controlWeapons(player.shooting && !boosted);
}
});
}
public static void drawMassPayloadLink(PayloadMassDriver.PayloadDriverBuild from){
Groups.build.each(b -> b instanceof PayloadMassDriver.PayloadDriverBuild fromMass &&
world.build(fromMass.link) == from &&
from.within(fromMass.x, fromMass.y, ((PayloadMassDriver)fromMass.block).range) &&
!linkedPayloadMasses.contains(from), b -> {
linkedPayloadMasses.add((PayloadMassDriver.PayloadDriverBuild) b);
drawMassPayloadLink((PayloadMassDriver.PayloadDriverBuild) b);
});
if(world.build(from.link) instanceof PayloadMassDriver.PayloadDriverBuild to && from != to &&
to.within(from.x, from.y, ((PayloadMassDriver)from.block).range)){
float sin = Mathf.absin(Time.time, 6f, 1f);
Tmp.v1.set(from.x + from.block.offset, from.y + from.block.offset).sub(to.x, to.y).limit(from.block.size * tilesize + sin + 0.5f);
float x2 = from.x - Tmp.v1.x, y2 = from.y - Tmp.v1.y,
x1 = to.x + Tmp.v1.x, y1 = to.y + Tmp.v1.y;
int segs = (int)(to.dst(from.x, from.y)/tilesize);
Lines.stroke(4f, Pal.gray);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(2f, Pal.placing);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(1f, Pal.accent);
Drawf.circles(from.x, from.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f, Pal.accent);
for(var shooter : from.waitingShooters){
Drawf.circles(shooter.x, shooter.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(shooter.x, shooter.y, from.x, from.y, from.block.size * tilesize + sin, 4f + sin);
}
if(from.link != -1 && world.build(from.link) instanceof PayloadMassDriver.PayloadDriverBuild other && other.block == from.block && other.team == from.team && from.within(other, ((PayloadMassDriver)from.block).range)){
Building target = world.build(from.link);
Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(from.x, from.y, target.x, target.y, from.block.size * tilesize + sin, 4f + sin);
}
if(world.build(to.link) instanceof PayloadMassDriver.PayloadDriverBuild newTo && to != newTo &&
newTo.within(to.x, to.y, ((PayloadMassDriver)to.block).range) && !linkedPayloadMasses.contains(to)){
linkedPayloadMasses.add(to);
drawMassPayloadLink(to);
}
}
}
public static void drawMassLink(MassDriver.MassDriverBuild from){
Groups.build.each(b -> b instanceof MassDriver.MassDriverBuild fromMass &&
world.build(fromMass.link) == from &&
from.within(fromMass.x, fromMass.y, ((MassDriver)fromMass.block).range) &&
!linkedMasses.contains(from), b -> {
linkedMasses.add((MassDriver.MassDriverBuild) b);
drawMassLink((MassDriver.MassDriverBuild) b);
});
if(world.build(from.link) instanceof MassDriver.MassDriverBuild to && from != to && to.within(from.x, from.y, ((MassDriver)from.block).range)){
float sin = Mathf.absin(Time.time, 6f, 1f);
Tmp.v1.set(from.x + from.block.offset, from.y + from.block.offset).sub(to.x, to.y).limit(from.block.size * tilesize + sin + 0.5f);
float x2 = from.x - Tmp.v1.x, y2 = from.y - Tmp.v1.y,
x1 = to.x + Tmp.v1.x, y1 = to.y + Tmp.v1.y;
int segs = (int)(to.dst(from.x, from.y)/tilesize);
Lines.stroke(4f, Pal.gray);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(2f, Pal.placing);
Lines.dashLine(x1, y1, x2, y2, segs);
Lines.stroke(1f, Pal.accent);
Drawf.circles(from.x, from.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f, Pal.accent);
for(var shooter : from.waitingShooters){
Drawf.circles(shooter.x, shooter.y, (from.tile.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(shooter.x, shooter.y, from.x, from.y, from.block.size * tilesize + sin, 4f + sin);
}
if(from.link != -1 && world.build(from.link) instanceof MassDriver.MassDriverBuild other && other.block == from.block && other.team == from.team && from.within(other, ((MassDriver)from.block).range)){
Building target = world.build(from.link);
Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f);
Drawf.arrow(from.x, from.y, target.x, target.y, from.block.size * tilesize + sin, 4f + sin);
}
if(world.build(to.link) instanceof MassDriver.MassDriverBuild newTo && to != newTo &&
newTo.within(to.x, to.y, ((MassDriver)to.block).range) && !linkedMasses.contains(to)){
linkedMasses.add(to);
drawMassLink(to);
}
}
}
public static Seq<Building> getPowerLinkedBuilds(Building build) {
Seq<Building> linkedBuilds = new Seq<>();
build.power.links.each(i -> linkedBuilds.add(world.build(i)));
build.proximity().each(linkedBuilds::add);
linkedBuilds.filter(b -> b != null && b.power != null);
if(!build.block.outputsPower && !(build instanceof PowerNode.PowerNodeBuild))
linkedBuilds.filter(b -> b.block.outputsPower || b instanceof PowerNode.PowerNodeBuild);
return linkedBuilds;
}
public static void drawNodeLink(Building node) {
if(node.power == null) return;
if(!linkedNodes.contains(node)) {
linkedNodes.add(node);
getPowerLinkedBuilds(node).each(other -> {
float angle1 = Angles.angle(node.x, node.y, other.x, other.y),
vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1),
len1 = node.block.size * tilesize / 2f - 1.5f, len2 = other.block.size * tilesize / 2f - 1.5f;
Draw.color(Color.white, Color.valueOf("98ff98"), (1f - node.power.graph.getSatisfaction()) * 0.86f + Mathf.absin(3f, 0.1f));
Draw.alpha(Renderer.laserOpacity);
Drawf.laser(node.team, atlas.find("unitinfo-Slaser"), atlas.find("unitinfo-Slaser-end"), node.x + vx*len1, node.y + vy*len1, other.x - vx*len2, other.y - vy*len2, 0.25f);
if(other.power != null) getPowerLinkedBuilds(other).each(OverDrawer::drawNodeLink);
});
}
}
}