// Returns the closest non-blocking tile to pos, or returns pos if no non-blocking tiles are present within a 2 tile distance. static Position findNonblockingPosition(Position pos, PROPULSION_TYPE propulsion, int player = 0, FPATH_MOVETYPE moveType = FMT_BLOCK) { Vector2i centreTile = map_coord(pos.xy); if (!fpathBaseBlockingTile(centreTile.x, centreTile.y, propulsion, player, moveType)) { return pos; // Fast case, pos is not on a blocking tile. } Vector2i bestTile = centreTile; int bestDistSq = INT32_MAX; for (int y = -2; y <= 2; ++y) for (int x = -2; x <= 2; ++x) { Vector2i tile = centreTile + Vector2i(x, y); Vector2i diff = world_coord(tile) + Vector2i(TILE_UNITS / 2, TILE_UNITS / 2) - pos.xy; int distSq = diff * diff; if (distSq < bestDistSq && !fpathBaseBlockingTile(tile.x, tile.y, propulsion, player, moveType)) { bestTile = tile; bestDistSq = distSq; } } // Return point on tile closest to the original pos. Vector2i minCoord = world_coord(bestTile); Vector2i maxCoord = minCoord + Vector2i(TILE_UNITS - 1, TILE_UNITS - 1); return Position(std::min(std::max(pos.x, minCoord.x), maxCoord.x), std::min(std::max(pos.y, minCoord.y), maxCoord.y), pos.z); }
void fpathSetBlockingMap(PATHJOB *psJob) { if (fpathCurrentGameTime != gameTime) { // New tick, remove maps which are no longer needed. fpathCurrentGameTime = gameTime; fpathPrevBlockingMaps.swap(fpathBlockingMaps); fpathBlockingMaps.clear(); } // Figure out which map we are looking for. PathBlockingType type; type.gameTime = gameTime; type.propulsion = psJob->propulsion; type.owner = psJob->owner; type.moveType = psJob->moveType; // Find the map. std::list<PathBlockingMap>::iterator i = std::find(fpathBlockingMaps.begin(), fpathBlockingMaps.end(), type); if (i == fpathBlockingMaps.end()) { // Didn't find the map, so i does not point to a map. fpathBlockingMaps.push_back(PathBlockingMap()); --i; // i now points to an empty map with no data. Fill the map. i->type = type; std::vector<bool> &map = i->map; map.resize(mapWidth*mapHeight); uint32_t checksumMap = 0, checksumDangerMap = 0, factor = 0; for (int y = 0; y < mapHeight; ++y) for (int x = 0; x < mapWidth; ++x) { map[x + y*mapWidth] = fpathBaseBlockingTile(x, y, type.propulsion, type.owner, type.moveType); checksumMap ^= map[x + y*mapWidth]*(factor = 3*factor + 1); } if (!isHumanPlayer(type.owner) && type.moveType == FMT_MOVE) { std::vector<bool> &dangerMap = i->dangerMap; dangerMap.resize(mapWidth*mapHeight); for (int y = 0; y < mapHeight; ++y) for (int x = 0; x < mapWidth; ++x) { dangerMap[x + y*mapWidth] = auxTile(x, y, type.owner) & AUXBITS_THREAT; checksumDangerMap ^= map[x + y*mapWidth]*(factor = 3*factor + 1); } } syncDebug("blockingMap(%d,%d,%d,%d) = %08X %08X", gameTime, psJob->propulsion, psJob->owner, psJob->moveType, checksumMap, checksumDangerMap); } else { syncDebug("blockingMap(%d,%d,%d,%d) = cached", gameTime, psJob->propulsion, psJob->owner, psJob->moveType); } // i now points to the correct map. Make psJob->blockingMap point to it. psJob->blockingMap = &*i; }
// Check if the map tile at a location blocks a droid bool fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion) { return fpathBaseBlockingTile(x, y, propulsion, 0, FMT_BLOCK); // with FMT_BLOCK, it is irrelevant which player is passed in }
bool fpathDroidBlockingTile(DROID *psDroid, int x, int y, FPATH_MOVETYPE moveType) { return fpathBaseBlockingTile(x, y, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType); }