Hitscan attacks hit invisible barriers in large open areas



Sometimes hitscans may hit an invisible barrier. This is caused by the fact that Doom has some difficulty handling the collision of bullets against very long walls. Projectiles will not be blocked by this invisible barrier, but it does block autoaim, potentially making projectile shots miss. This bug happens more frequently on levels where there are walls that are more than 2048 units long.

Technical explanation of the hitscan collision error
When a wall is very long, the engine may incorrectly evaluate the position of the wall.

The technical explanation as how it occurs is yet unknown, but a particular case is known that mappers should avoid: linedef #0 should always be shorter than 2048 units long. This greatly reduces the occurrence of the bug, because essentially all blockmap generating utilities apart from ZokumBSP will always include linedef #0 in each block of the blockmap. Although this is the most common cause of this bug, it may also occur when a hitscan crosses a block that contains another long linedef.

Technical explanation of the most common case
To understand this case, the structure of the blockmap must be first understood. Each block of the blockmap contains a list (blocklist) of linedefs that touches or may touch the block. The blocklist always starts with the value and ends with. Most utilities will include the number at the start of the list although it's not a technical necessity and the Doom engine will not skip it.

This is the essential part of the function from :

offset = y*bmapwidth+x; offset = *(blockmap+offset); for ( list = blockmaplump+offset ; *list != -1 ; list++) {       ld = &lines[*list]; if (ld->validcount == validcount) continue; 	// line has already been checked ld->validcount = validcount; if ( !func(ld) ) return false; }   return true;	// everything was checked

The loop will iterate over the list and it starts at the beginning of the blocklist which has the value until it reaches the end. Each element on the list is the number of a linedef, but since the iteration starts on the first element which is often, but not always, then linedef #0 is constantly checked each time the function is called. Since it's done whenever the player fires, the bug is more inclined to occur on a level where this linedef is too long.

A quick and dirty fix would be to add to, but hitscan errors may still occur against other walls which are too long. Doing this will break map compatibility severely with maps made with newer utilities that can omit the lindef 0 entry for reasons of optimization and less buggy gameplay. Skipping the checks for the first linedef will also break demo compatibility with ports that do not have this change. A better solution would be that the mapper omits adding the faulty lindef 0 entries in the first place instead of adding a workaround in the source ports. Such maps would be incompatible with several source ports that skip entry 0 without checking if it is a valid linedef or not. BTSX E2 MAP20 is an example of a map without leading 0 entries in block lists.

A good habit for map developers is to break long walls into linedefs smaller than 1024 units long, which will also reduce the visibility of the long wall error at the same time.

Demo files

 * [[Media:E3M6hsb.lmp|Demonstration of the bug]] (file info) on E3M6: Mt. Erebus