/** * Check whether a river could (logically) flow into a lock. * @param tile the middle tile of a lock. * @recursive whether the function is being called recursively. * @return true iff the water can be flowing into a lock. */ bool FlowsLock(TileIndex tile, bool recursive = false) { DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile)); if (dir == INVALID_DIAGDIR) return false; int delta_mid = TileOffsByDiagDir(dir); if (!IsTileFlat(tile + delta_mid)) return false; if (!IsTileFlat(tile - delta_mid)) return false; if (!recursive) return true; DiagDirection dir_rot = ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT); int delta = TileOffsByDiagDir(dir_rot); for (int m = -1; m <= 1; m += 2) { if (IsValidTile(tile + m * delta_mid)) { if (DistanceFromEdgeDir(tile + m * delta_mid, dir) == 0 || DistanceFromEdgeDir(tile + m * delta_mid, ReverseDiagDir(dir)) == 0) { return false; } if (IsValidTile(tile + m * 2 * delta_mid)) { if (!IsTileFlat(tile + m * 2 * delta_mid)) { return false; } if (IsValidTile(tile + m * 3 * delta_mid)) { if ((GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid)) == dir || GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid)) == ReverseDiagDir(dir)) && FlowsLock(tile + m * 3 * delta_mid)) { return false; } } } } for (int d = -1; d <= 1; d += 2) { if (IsValidTile(tile + m * delta_mid + d * delta)) { if (!IsTileFlat(tile + m * delta_mid + d * delta) && (GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * delta)) == dir_rot || GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * delta)) == ReverseDiagDir(dir_rot)) && FlowsLock(tile + m * delta_mid + d * delta)) { return false; } if (IsValidTile(tile + m * delta_mid + d * 2 * delta)) { if (!IsTileFlat(tile + m * delta_mid + d * 2 * delta) && (GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * 2 * delta)) == dir_rot || GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * 2 * delta)) == ReverseDiagDir(dir_rot)) && FlowsLock(tile + m * delta_mid + d * 2 * delta)) { return false; } } if (IsValidTile(tile + m * 2 * delta_mid + d * delta)) { if (IsTileFlat(tile + m * delta_mid + d * delta) && !IsTileFlat(tile + m * 2 * delta_mid + d * delta)) { return false; } if (!IsTileFlat(tile + m * 2 * delta_mid + d * delta) && (GetInclinedSlopeDirection(GetTileSlope(tile + m * 2 * delta_mid + d * delta)) == dir_rot || GetInclinedSlopeDirection(GetTileSlope(tile + m * 2 * delta_mid + d * delta)) == ReverseDiagDir(dir_rot)) && FlowsLock(tile + m * 2 * delta_mid + d * delta)) { return false; } if (IsValidTile(tile + m * 3 * delta_mid + d * delta)) { if ((GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid + d * delta)) == dir || GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid + d * delta)) == ReverseDiagDir(dir)) && FlowsLock(tile + m * 3 * delta_mid + d * delta)) { return false; } } } } } } return true; } /** * Check whether a river at begin could (logically) flow down to end. * @param begin The origin of the flow. * @param end The destination of the flow. * @return True iff the water can be flowing down. */ static bool FlowsDown(TileIndex begin, TileIndex end) { assert(DistanceManhattan(begin, end) == 1); int heightBegin; int heightEnd; Slope slopeBegin = GetTileSlope(begin, &heightBegin); Slope slopeEnd = GetTileSlope(end, &heightEnd); return heightEnd <= heightBegin && /* Slope either is inclined or flat; rivers don't support other slopes. */ (slopeEnd == SLOPE_FLAT || (IsInclinedSlope(slopeEnd) && FlowsLock(end, true))) && /* Slope continues, then it must be lower... or either end must be flat. */ ((slopeEnd == slopeBegin && heightEnd < heightBegin) || slopeEnd == SLOPE_FLAT || (slopeBegin == SLOPE_FLAT && GetTileMaxZ(end) == heightBegin)); }