Interesting, it even affects Mocha (both when using its own and the prBoom+ loading code). For now I can say that P_BlockLinesIterator isn't even called at least when the player is in the first room, but clipping works for the distant smaller room. Forcing an internal blockmap rebuild with -blockmap doesn't seem to solve the problem.
The problem was in P_CheckPosition:
// check lines
xl = (tmbbox[BOXLEFT] - LL.bmaporgx)>>MAPBLOCKSHIFT;
xh = (tmbbox[BOXRIGHT] - LL.bmaporgx)>>MAPBLOCKSHIFT;
yl = (tmbbox[BOXBOTTOM] - LL.bmaporgy)>>MAPBLOCKSHIFT;
yh = (tmbbox[BOXTOP] - LL.bmaporgy)>>MAPBLOCKSHIFT;
To express the difference between the blockmap origins and your current position, you actually need at least 9 UNSIGNED bits to express a maximum difference of 512 blocks = 512*128=64K map units.
However that signed shift destroys the top bit, resulting in a -256...255 range.
The starting room is actually at a block coordinate > 255 which results in negative block number (xl xh yl yh: -245 -245 0 1) , thus BlockLinesIterator is never called. It's a well-known limitation of the blockmap system which practically limits blockmaps to a maximum of 256 x 256 addressable blocks through MAPBLOCKSHIFT (=23), regardless of map extension.
The isolated room has a block coord of xl, yl : 21 21 so it has no problem clipping properly .
About solving it...a general solution that can remove ALL blockmap limits would require fixing a lot of stuff along the line.
HOWEVER, I came up with a quick and dirty hack:
First, in P_CheckLine, use an unsigned shift so that you get values
from 0..511 instead of -256...255 for the blockmap coords.
// check lines
xl = (tmbbox[BOXLEFT] - LL.bmaporgx)>>>MAPBLOCKSHIFT;
xh = (tmbbox[BOXRIGHT] - LL.bmaporgx)>>>MAPBLOCKSHIFT;
yl = (tmbbox[BOXBOTTOM] - LL.bmaporgy)>>>MAPBLOCKSHIFT;
yh = (tmbbox[BOXTOP] - LL.bmaporgy)>>>MAPBLOCKSHIFT;
Then do this simple sanity check: If you get any blockmap coords that are clearly beyond the stated blockmap width/height, then you are actually outside of the blockmap (either too positive or too negative, doesn't matter. The check should be made more refined, I know, to understand whether you have just went from e.g. to -1,-1 from 0,0 in a decreasing fashion or whether you went beyond bmapwidth/bmapheight in an increasing fashion.
// Maes's quick and dirty blockmap extension hack
if (xl>LL.bmapwidth) xl=0; // Broke width boundary
if (xh>LL.bmapwidth) xh=0; // Broke width boundary
if (yh>LL.bmapheight) yl=0; // Broke height boundary
if (yl>LL.bmapheight) yl=0; // Broke height boundary
In any case, this gives you an effective addressable blockmap size of 512*512 blocks, which means that you can now cover the full range of +/- 32K coords (512*128 = 64K). The only problem is that you can't express negative offsets relative to the blockmap, which may affect some tricks that rely travelling through the void. In order to do that you'd have to switch to a 10-bit signed blockmap index, of which you'd use the -512..-1 range to ensure void trick compatibility.
You could however leave the signed shift in-place, and interpret some particular negative values as being indicative of an extended blockmap, and others as simply being indicative of having moved before the blockmap origin.
E.g. for a blockmap of size 257 * 257, an index of -256 should be interpreted as +256, +256 while one of -128 simply as -128, thus preserving negativity. This would also fully preserve the behavior of blockmaps that don't exceed the 0.255 limits.
Last edited by Maes on 12-02-11 at 13:06