diff --git a/core/assets/maps/atolls.msav b/core/assets/maps/atolls.msav index 1768c32aaf..02f2737deb 100644 Binary files a/core/assets/maps/atolls.msav and b/core/assets/maps/atolls.msav differ diff --git a/core/src/mindustry/ai/types/CommandAI.java b/core/src/mindustry/ai/types/CommandAI.java index 8ba3e24be1..283f2a8367 100644 --- a/core/src/mindustry/ai/types/CommandAI.java +++ b/core/src/mindustry/ai/types/CommandAI.java @@ -272,6 +272,13 @@ public class CommandAI extends AIController{ vecOut.set(vecMovePos); }else{ move = controlPath.getPathPosition(unit, vecMovePos, targetPos, vecOut, noFound) && (!blockingUnit || timeSpentBlocked > maxBlockTime); + + //TODO: what to do when there's a target and it can't be reached? + /* + if(noFound[0] && attackTarget != null && attackTarget.within(unit, unit.type.range * 2f)){ + move = true; + vecOut.set(targetPos); + }*/ } //rare case where unit must be perfectly aligned (happens with 1-tile gaps) @@ -403,6 +410,11 @@ public class CommandAI extends AIController{ } } + @Override + public void removed(Unit unit){ + clearCommands(); + } + public void commandQueue(Position location){ if(targetPos == null && attackTarget == null){ if(location instanceof Teamc t){ @@ -444,7 +456,7 @@ public class CommandAI extends AIController{ @Override public Teamc findTarget(float x, float y, float range, boolean air, boolean ground){ - return !nearAttackTarget(x, y, range) ? super.findTarget(x, y, range, air, ground) : attackTarget; + return !nearAttackTarget(x, y, range) ? super.findTarget(x, y, range, air, ground) : Units.isHittable(attackTarget, air, ground) ? attackTarget : null; } public boolean nearAttackTarget(float x, float y, float range){ diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java index b9f718b8a3..a412c6f4da 100644 --- a/core/src/mindustry/ai/types/FlyingAI.java +++ b/core/src/mindustry/ai/types/FlyingAI.java @@ -10,6 +10,7 @@ import static mindustry.Vars.*; import static mindustry.world.meta.BlockFlag.*; public class FlyingAI extends AIController{ + final static Rand rand = new Rand(); final static BlockFlag[] randomTargets = {core, storage, generator, launchPad, factory, repair, battery, reactor, drill}; @Override @@ -72,10 +73,10 @@ public class FlyingAI extends AIController{ if(state.rules.randomWaveAI){ //when there are no waves, it's just random based on the unit - Mathf.rand.setSeed(unit.type.id + (state.rules.waves ? state.wave : unit.id)); + rand.setSeed(unit.type.id + (state.rules.waves ? state.wave : unit.id)); //try a few random flags first for(int attempt = 0; attempt < 5; attempt++){ - Teamc result = targetFlag(x, y, randomTargets[Mathf.rand.random(randomTargets.length - 1)], true); + Teamc result = targetFlag(x, y, randomTargets[rand.random(randomTargets.length - 1)], true); if(result != null) return result; } //try the closest target diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index d74b41dad5..d334651092 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -112,6 +112,10 @@ public class Units{ return player == null || tile == null || tile.interactable(player.team()) || state.rules.editor; } + public static boolean isHittable(@Nullable Posc target, boolean air, boolean ground){ + return target != null && (target instanceof Buildingc ? ground : (target instanceof Unit u && u.checkTarget(air, ground))); + } + /** * Validates a target. * @param target The target to validate diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index 9cf23876d2..0122166c94 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -90,6 +90,8 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ } void pickup(Unit unit){ + if(unit.isAdded()) unit.team.data().updateCount(unit.type, 1); + unit.remove(); addPayload(new UnitPayload(unit)); Fx.unitPickup.at(unit); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 48d6d9c6b7..9b8f16bb42 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -457,7 +457,7 @@ public class DesktopInput extends InputHandler{ cursorType = cursor.build.getCursor(); } - if(cursor.build != null && !state.rules.editor && player.team() != Team.derelict && cursor.build.team == Team.derelict && cursor.build.block.unlockedNow() && Build.validPlace(cursor.block(), player.team(), cursor.build.tileX(), cursor.build.tileY(), cursor.build.rotation)){ + if(canRepairDerelict(cursor)){ cursorType = ui.repairCursor; } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index f3d7fa84cf..66fe7933a2 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -53,6 +53,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ /** Used for dropping items. */ final static float playerSelectRange = mobile ? 17f : 11f; final static IntSeq removed = new IntSeq(); + final static IntSet intSet = new IntSet(); /** Maximum line length. */ final static int maxLength = 100; final static Rect r1 = new Rect(), r2 = new Rect(); @@ -1383,10 +1384,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y); } - protected void drawRebuildSelection(int x, int y, int x2, int y2){ - drawSelection(x, y, x2, y2, 0, Pal.sapBulletBack, Pal.sapBullet); + protected void drawRebuildSelection(int x1, int y1, int x2, int y2){ + drawSelection(x1, y1, x2, y2, 0, Pal.sapBulletBack, Pal.sapBullet); - NormalizeDrawResult result = Placement.normalizeDrawArea(Blocks.air, x, y, x2, y2, false, 0, 1f); + NormalizeDrawResult result = Placement.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, 0, 1f); Tmp.r1.set(result.x, result.y, result.x2 - result.x, result.y2 - result.y); @@ -1396,6 +1397,20 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ drawSelected(plan.x, plan.y, content.block(plan.block), Pal.sapBullet); } } + + NormalizeResult dresult = Placement.normalizeArea(x1, y1, x2, y2, rotation, false, 999999999); + + intSet.clear(); + for(int x = dresult.x; x <= dresult.x2; x++){ + for(int y = dresult.y; y <= dresult.y2; y++){ + + Tile tile = world.tileBuilding(x, y); + + if(tile != null && intSet.add(tile.pos()) && canRepairDerelict(tile)){ + drawSelected(tile.x, tile.y, tile.block(), Pal.sapBullet); + } + } + } } protected void drawBreakSelection(int x1, int y1, int x2, int y2){ @@ -1684,13 +1699,20 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } boolean tryRepairDerelict(Tile selected){ - if(selected != null && !state.rules.editor && player.team() != Team.derelict && selected.build != null && selected.build.block.unlockedNow() && selected.build.team == Team.derelict && Build.validPlace(selected.block(), player.team(), selected.build.tileX(), selected.build.tileY(), selected.build.rotation)){ + if(selected != null && !state.rules.editor && player.team() != Team.derelict && selected.build != null && selected.build.block.unlockedNow() && selected.build.team == Team.derelict && + Build.validPlace(selected.block(), player.team(), selected.build.tileX(), selected.build.tileY(), selected.build.rotation)){ + player.unit().addBuild(new BuildPlan(selected.build.tileX(), selected.build.tileY(), selected.build.rotation, selected.block(), selected.build.config())); return true; } return false; } + boolean canRepairDerelict(Tile tile){ + return tile != null && tile.build != null && !state.rules.editor && player.team() != Team.derelict && tile.build.team == Team.derelict && tile.build.block.unlockedNow() && + Build.validPlace(tile.block(), player.team(), tile.build.tileX(), tile.build.tileY(), tile.build.rotation); + } + boolean canMine(Tile tile){ return !Core.scene.hasMouse() && player.unit().validMine(tile) @@ -1898,8 +1920,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } - public void rebuildArea(int x, int y, int x2, int y2){ - NormalizeResult result = Placement.normalizeArea(x, y, x2, y2, rotation, false, 999999999); + public void rebuildArea(int x1, int y1, int x2, int y2){ + NormalizeResult result = Placement.normalizeArea(x1, y1, x2, y2, rotation, false, 999999999); Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize); Iterator broken = player.team().data().plans.iterator(); @@ -1910,6 +1932,18 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ player.unit().addBuild(new BuildPlan(plan.x, plan.y, plan.rotation, content.block(plan.block), plan.config)); } } + + intSet.clear(); + for(int x = result.x; x <= result.x2; x++){ + for(int y = result.y; y <= result.y2; y++){ + + Tile tile = world.tileBuilding(x, y); + + if(tile != null && tile.build != null && intSet.add(tile.pos())){ + tryRepairDerelict(tile); + } + } + } } public void tryBreakBlock(int x, int y){ diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 1eb43fec67..3819a23e3c 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -1276,7 +1276,9 @@ public class UnitType extends UnlockableContent implements Senseable{ if(drawCell) drawCell(unit); drawWeapons(unit); if(drawItems) drawItems(unit); - drawLight(unit); + if(!isPayload){ + drawLight(unit); + } if(unit.shieldAlpha > 0 && drawShields){ drawShield(unit);