package mindustry.entities; import arc.func.*; import arc.math.*; import arc.math.geom.*; import mindustry.entities.type.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.world.*; import static mindustry.Vars.*; /** Utility class for unit and team interactions.*/ public class Units{ private static Rect hitrect = new Rect(); private static Unitc result; private static float cdist; private static boolean boolResult; /** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/ public static boolean canInteract(Player player, Tile tile){ return player == null || tile == null || tile.interactable(player.team()); } /** * Validates a target. * @param target The target to validate * @param team The team of the thing doing tha targeting * @param x The X position of the thing doign the targeting * @param y The Y position of the thing doign the targeting * @param range The maximum distance from the target X/Y the targeter can be for it to be valid * @return whether the target is invalid */ public static boolean invalidateTarget(Teamc target, Team team, float x, float y, float range){ return target == null || (range != Float.MAX_VALUE && !target.withinDst(x, y, range)) || target.team() == team || !target.isValid(); } /** See {@link #invalidateTarget(Teamc, Team, float, float, float)} */ public static boolean invalidateTarget(Teamc target, Team team, float x, float y){ return invalidateTarget(target, team, x, y, Float.MAX_VALUE); } /** See {@link #invalidateTarget(Teamc, Team, float, float, float)} */ public static boolean invalidateTarget(Teamc target, Unitc targeter){ return invalidateTarget(target, targeter.team(), targeter.x, targeter.y, targeter.getWeapon().bullet.range()); } /** Returns whether there are any entities on this tile. */ public static boolean anyEntities(Tile tile){ float size = tile.block().size * tilesize; return anyEntities(tile.drawx() - size/2f, tile.drawy() - size/2f, size, size); } public static boolean anyEntities(float x, float y, float width, float height){ boolResult = false; nearby(x, y, width, height, unit -> { if(boolResult) return; if(!unit.isFlying()){ unit.hitbox(hitrect); if(hitrect.overlaps(x, y, width, height)){ boolResult = true; } } }); return boolResult; } /** Returns the neareset damaged tile. */ public static Tilec findDamagedTile(Team team, float x, float y){ Tile tile = Geometry.findClosest(x, y, indexer.getDamaged(team)); return tile == null ? null : tile.entity; } /** Returns the neareset ally tile in a range. */ public static Tilec findAllyTile(Team team, float x, float y, float range, Boolf pred){ return indexer.findTile(team, x, y, range, pred); } /** Returns the neareset enemy tile in a range. */ public static Tilec findEnemyTile(Team team, float x, float y, float range, Boolf pred){ if(team == Team.derelict) return null; return indexer.findEnemyTile(team, x, y, range, pred); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ public static Teamc closestTarget(Team team, float x, float y, float range){ return closestTarget(team, x, y, range, Unitc::isValid); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ public static Teamc closestTarget(Team team, float x, float y, float range, Boolf unitPred){ return closestTarget(team, x, y, range, unitPred, t -> true); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ public static Teamc closestTarget(Team team, float x, float y, float range, Boolf unitPred, Boolf tilePred){ if(team == Team.derelict) return null; Unitc unit = closestEnemy(team, x, y, range, unitPred); if(unit != null){ return unit; }else{ return findEnemyTile(team, x, y, range, tilePred); } } /** Returns the closest enemy of this team. Filter by predicate. */ public static Unitc closestEnemy(Team team, float x, float y, float range, Boolf predicate){ if(team == Team.derelict) return null; result = null; cdist = 0f; nearbyEnemies(team, x - range, y - range, range*2f, range*2f, e -> { if(e.dead() || !predicate.get(e)) return; float dst2 = Mathf.dst2(e.x, e.y, x, y); if(dst2 < range*range && (result == null || dst2 < cdist)){ result = e; cdist = dst2; } }); return result; } /** Returns the closest ally of this team. Filter by predicate. */ public static Unitc closest(Team team, float x, float y, float range, Boolf predicate){ result = null; cdist = 0f; nearby(team, x, y, range, e -> { if(!predicate.get(e)) return; float dist = Mathf.dst2(e.x, e.y, x, y); if(result == null || dist < cdist){ result = e; cdist = dist; } }); return result; } /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ unitGroup.intersect(x, y, width, height, u -> { if(u.getTeam() == team){ cons.get(u); } }); } /** Iterates over all units in a circle around this position. */ public static void nearby(Team team, float x, float y, float radius, Cons cons){ unitGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { if(unit.getTeam() == team && unit.withinDst(x, y, radius)){ cons.get(unit); } }); } /** Iterates over all units in a rectangle. */ public static void nearby(float x, float y, float width, float height, Cons cons){ unitGroup.intersect(x, y, width, height, cons); } /** Iterates over all units in a rectangle. */ public static void nearby(Rect rect, Cons cons){ nearby(rect.x, rect.y, rect.width, rect.height, cons); } /** Iterates over all units that are enemies of this team. */ public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ unitGroup.intersect(x, y, width, height, u -> { if(team.isEnemy(u.getTeam())){ cons.get(u); } }); } /** Iterates over all units that are enemies of this team. */ public static void nearbyEnemies(Team team, Rect rect, Cons cons){ nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons); } /** Iterates over all units. */ public static void all(Cons cons){ unitGroup.all().each(cons); } public static void each(Team team, Cons cons){ unitGroup.all().each(t -> t.getTeam() == team, cons); } }