@@ -692,16 +692,16 @@ public List<Unit> getUnitsOnTile(final int tileX, final int tileY) {
692692 * given build tile.
693693 */
694694 public List <Unit > getUnitsOnTile (final int tileX , final int tileY , final UnitFilter pred ) {
695- final TilePosition tile = new TilePosition (tileX , tileY );
696- if (!tile .isValid (this )) {
695+ final int x = tileX * TilePosition .SIZE_IN_PIXELS ;
696+ final int y = tileY * TilePosition .SIZE_IN_PIXELS ;
697+ if (tileX < 0 || tileY < 0 || x >= mapPixelWidth () || y >= mapPixelHeight ()) {
697698 return Collections .emptyList ();
698699 }
699- final Position p = tile .toPosition ();
700- return getUnitsInRectangle (p .x , p .y , p .x + 32 , p .y + 32 , pred );
700+ return getUnitsInRectangle (x , y , x + 32 , y + 32 , pred );
701701 }
702702
703703 public List <Unit > getUnitsInRectangle (final int left , final int top , final int right , final int bottom ) {
704- return getUnitsInRectangle (left , top , right , bottom , u -> true );
704+ return getUnitsInRectangle (left , top , right , bottom , null );
705705 }
706706
707707 /**
@@ -716,13 +716,17 @@ public List<Unit> getUnitsInRectangle(final int left, final int top, final int r
716716 * given rectangle bounds.
717717 */
718718 public List <Unit > getUnitsInRectangle (final int left , final int top , final int right , final int bottom , final UnitFilter pred ) {
719- return getAllUnits ().stream ()
720- .filter (u -> left <= u .getRight () && top <= u .getBottom () && right >= u .getLeft () && bottom >= u .getTop () && pred .test (u ))
721- .collect (Collectors .toList ());
719+ final List <Unit > result = new ArrayList <>();
720+ for (final Unit u : getAllUnits ()) {
721+ if (Unit .overlapsRectangle (u , left , top , right , bottom ) && (pred == null || pred .test (u ))) {
722+ result .add (u );
723+ }
724+ }
725+ return result ;
722726 }
723727
724728 public List <Unit > getUnitsInRectangle (final Position leftTop , final Position rightBottom ) {
725- return getUnitsInRectangle (leftTop .x , leftTop .y , rightBottom .x , rightBottom .y , u -> true );
729+ return getUnitsInRectangle (leftTop .x , leftTop .y , rightBottom .x , rightBottom .y , null );
726730 }
727731
728732 public List <Unit > getUnitsInRectangle (final Position leftTop , final Position rightBottom , final UnitFilter pred ) {
@@ -1105,69 +1109,80 @@ public boolean canBuildHere(final TilePosition position, final UnitType type) {
11051109 */
11061110 public boolean canBuildHere (final TilePosition position , final UnitType type , final Unit builder , final boolean checkExplored ) {
11071111 // lt = left top, rb = right bottom
1108- final TilePosition lt = builder != null && type .isAddon () ?
1109- position . add ( new TilePosition ( 4 , 1 )) : // addon build offset
1110- position ;
1111- final TilePosition rb = lt . add ( type .tileSize () );
1112+ final int ltX = builder != null && type .isAddon () ? position . x + 4 : position . x ;
1113+ final int ltY = builder != null && type . isAddon () ? position . y + 1 : position . y ;
1114+ final int rbX = ltX + type . tileWidth () ;
1115+ final int rbY = ltY + type .tileHeight ( );
11121116
11131117 // Map limit check
1114- if (!lt . isValid ( this ) || !( rb . toPosition (). subtract ( new Position ( 1 , 1 )). isValid ( this ) )) {
1118+ if (!isValidTile ( ltX , ltY ) || !isValidPosition ( rbX * TilePosition . SIZE_IN_PIXELS - 1 , rbY * TilePosition . SIZE_IN_PIXELS - 1 )) {
11151119 return false ;
11161120 }
11171121
11181122 //if the getUnit is a refinery, we just need to check the set of geysers to see if the position
11191123 //matches one of them (and the type is still vespene geyser)
11201124 if (type .isRefinery ()) {
11211125 for (final Unit g : getGeysers ()) {
1122- if (g .getTilePosition ().equals (lt )) {
1126+ final TilePosition tp = g .getTilePosition ();
1127+ if (tp .x == ltX && tp .y == ltY ) {
11231128 return !g .isVisible () || g .getType () == Resource_Vespene_Geyser ;
11241129 }
11251130 }
11261131 return false ;
11271132 }
11281133
11291134 // Tile buildability check
1130- for (int x = lt . x ; x < rb . x ; ++x ) {
1131- for (int y = lt . y ; y < rb . y ; ++y ) {
1135+ for (int x = ltX ; x < rbX ; ++x ) {
1136+ for (int y = ltY ; y < rbY ; ++y ) {
11321137 // Check if tile is buildable/unoccupied and explored.
11331138 if (!isBuildable (x , y ) || (checkExplored && !isExplored (x , y ))) {
11341139 return false ;
11351140 }
11361141 }
11371142 }
11381143
1144+ final int targPosX = ltX * TilePosition .SIZE_IN_PIXELS + (type .tileWidth () * TilePosition .SIZE_IN_PIXELS ) / 2 ;
1145+ final int targPosY = ltY * TilePosition .SIZE_IN_PIXELS + (type .tileHeight () * TilePosition .SIZE_IN_PIXELS ) / 2 ;
1146+
11391147 // Check if builder is capable of reaching the building site
11401148 if (builder != null ) {
1141- if (!builder .getType ().isBuilding ()) {
1142- if (!builder .hasPath (lt .toPosition ().add (type .tileSize ().toPosition ().divide (2 )))) {
1149+ final UnitType builderType = builder .getType ();
1150+ if (!builderType .isBuilding ()) {
1151+ if (!builder .hasPath (new Position (targPosX , targPosY ))) {
11431152 return false ;
11441153 }
1145- } else if (!builder . getType () .isFlyingBuilding () && type != Zerg_Nydus_Canal && !type .isFlagBeacon ()) {
1154+ } else if (!builderType .isFlyingBuilding () && type != Zerg_Nydus_Canal && !type .isFlagBeacon ()) {
11461155 return false ;
11471156 }
11481157 }
11491158
11501159 // Ground getUnit dimension check
11511160 if (type != Special_Start_Location ) {
1152- final Position targPos = lt .toPosition ().add (type .tileSize ().toPosition ().divide (2 ));
1153- final List <Unit > unitsInRect = getUnitsInRectangle (
1154- targPos .subtract (new Position (type .dimensionLeft (), type .dimensionUp ())),
1155- targPos .add (new Position (type .dimensionRight (), type .dimensionDown ())),
1156- u -> !u .isFlying () && !u .isLoaded () && (builder != u || type == Zerg_Nydus_Canal ));
1157-
1158- for (final Unit u : unitsInRect ) {
1159- // Addons can be placed over units that can move, pushing them out of the way
1160- if (!(type .isAddon () && u .getType ().canMove ())) {
1161- return false ;
1161+ final int rectLeft = targPosX - type .dimensionLeft ();
1162+ final int rectTop = targPosY - type .dimensionUp ();
1163+ final int rectRight = targPosX + type .dimensionRight ();
1164+ final int rectBottom = targPosY + type .dimensionDown ();
1165+ final boolean isAddon = type .isAddon ();
1166+ final boolean isNydus = type == Zerg_Nydus_Canal ;
1167+
1168+ for (final Unit u : getAllUnits ()) {
1169+ if (Unit .overlapsRectangle (u , rectLeft , rectTop , rectRight , rectBottom )
1170+ && !u .isFlying ()
1171+ && !u .isLoaded ()
1172+ && (builder != u || isNydus )) {
1173+ // Addons can be placed over units that can move, pushing them out of the way
1174+ if (!(isAddon && u .getType ().canMove ())) {
1175+ return false ;
1176+ }
11621177 }
11631178 }
11641179
11651180 // Creep Check
11661181 // Note: Zerg structures that don't require creep can still be placed on creep
11671182 final boolean needsCreep = type .requiresCreep ();
11681183 if (type .getRace () != Zerg || needsCreep ) {
1169- for (int x = lt . x ; x < rb . x ; ++x ) {
1170- for (int y = lt . y ; y < rb . y ; ++y ) {
1184+ for (int x = ltX ; x < rbX ; ++x ) {
1185+ for (int y = ltY ; y < rbY ; ++y ) {
11711186 if (needsCreep != hasCreep (x , y )) {
11721187 return false ;
11731188 }
@@ -1176,7 +1191,7 @@ public boolean canBuildHere(final TilePosition position, final UnitType type, fi
11761191 }
11771192
11781193 // Power Check
1179- if (type .requiresPsi () && !hasPower (lt , type )) {
1194+ if (type .requiresPsi () && !hasPower (ltX , ltY , type )) {
11801195 return false ;
11811196 }
11821197
@@ -1189,19 +1204,19 @@ public boolean canBuildHere(final TilePosition position, final UnitType type, fi
11891204 if ((isVisible (tp ) || isVisible (tp .x + 1 , tp .y )) && !m .exists ()) {
11901205 continue ; // tile position is visible, but mineral is not => mineral does not exist
11911206 }
1192- if (tp .x > lt . x - 5 &&
1193- tp .y > lt . y - 4 &&
1194- tp .x < lt . x + 7 &&
1195- tp .y < lt . y + 6 ) {
1207+ if (tp .x > ltX - 5 &&
1208+ tp .y > ltY - 4 &&
1209+ tp .x < ltX + 7 &&
1210+ tp .y < ltY + 6 ) {
11961211 return false ;
11971212 }
11981213 }
11991214 for (final Unit g : getStaticGeysers ()) {
12001215 final TilePosition tp = g .getInitialTilePosition ();
1201- if (tp .x > lt . x - 7 &&
1202- tp .y > lt . y - 5 &&
1203- tp .x < lt . x + 7 &&
1204- tp .y < lt . y + 6 ) {
1216+ if (tp .x > ltX - 7 &&
1217+ tp .y > ltY - 5 &&
1218+ tp .x < ltX + 7 &&
1219+ tp .y < ltY + 6 ) {
12051220 return false ;
12061221 }
12071222 }
@@ -1211,7 +1226,7 @@ public boolean canBuildHere(final TilePosition position, final UnitType type, fi
12111226 // then lands at the new location before building the addon), so we need to do similar checks for the
12121227 // location that the building will be when it builds the addon.
12131228 if (builder != null && !builder .getType ().isAddon () && type .isAddon ()) {
1214- return canBuildHere (lt . subtract ( new TilePosition (4 , 1 ) ), builder .getType (), builder , checkExplored );
1229+ return canBuildHere (new TilePosition (ltX - 4 , ltY - 1 ), builder .getType (), builder , checkExplored );
12151230 }
12161231
12171232 //if the build site passes all these tests, return true.
0 commit comments