Difference between revisions of "Monsters can see through walls"
From DoomWiki.org
[checked revision] | [checked revision] |
ETTiNGRiNDER (talk | contribs) (Someone more mathematically-minded should probably explain the technicalities of exactly why the line-of-sight calculations are buggy, but for now here's a mostly user-side view of the bug.) |
(Merge with ConSiGno's older "Anywhere Moo Bug" article) |
||
Line 1: | Line 1: | ||
− | Due to buggy line of sight calculations, monsters in vanilla [[Heretic]] may sometimes erroneously regard a player on the other side of | + | Due to buggy line of sight calculations, monsters in vanilla [[Heretic]] and [[Hexen]] may sometimes erroneously regard a player on the other side of any arbitrary number of walls as visible, causing them to wake and go into chase mode before it makes sense for them to do so. One name given to this bug is the '''"Anywhere Moo bug"''', named as such by [[James "Quasar" Haley]] who noted the bug was most readily observed with boss monsters such as the [[cyberdemon]] and [[maulotaur]], due to their wake sounds not decreasing in volume with distance.{{cite web|author=[[James Haley (Quasar)|Haley, James]]|title=Is it possible to... (Heretic source)|url={{Dwforumst|id=821468}}|publication=[[Doomworld Forums]]|publishdate=12 October 2009|accessdate=15 October 2021}} |
+ | |||
+ | This bug was inherited from early versions of the [[Doom]] codebase just prior to [[Versions of Doom and Doom II#v1.2|version v1.2]], and persisted into [[Heretic]], [[Hexen]], and was notably later adapted accidentally into the [[ZDoom]] [[source port]]. It was fixed by [[id Software]] via swapping the original [[BLOCKMAP]]-based line-of-sight (LOS) checking algorithm with one based on use of the [[BSP tree]]. | ||
==Designer workaround== | ==Designer workaround== | ||
Line 5: | Line 7: | ||
Any remaining problems after that may, with some concession of design, be alleviated by adjusting the angle the offending monsters are facing. | Any remaining problems after that may, with some concession of design, be alleviated by adjusting the angle the offending monsters are facing. | ||
+ | |||
+ | ==Algorithmic fix== | ||
+ | The corrected code, from ZDoom, is below: | ||
+ | |||
+ | for (count = 0 ; count < 100 ; count++) | ||
+ | { | ||
+ | if (flags & PT_ADDLINES) | ||
+ | { | ||
+ | AddLineIntercepts(mapx, mapy); | ||
+ | } | ||
+ | |||
+ | if (flags & PT_ADDTHINGS) | ||
+ | { | ||
+ | AddThingIntercepts(mapx, mapy, btit); | ||
+ | } | ||
+ | |||
+ | if (mapx == xt2 && mapy == yt2) | ||
+ | { | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | // [RH] Handle corner cases properly instead of pretending they don't exist. | ||
+ | switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx)) | ||
+ | { | ||
+ | case 0: // neither xintercept nor yintercept match! | ||
+ | count = 100; // Stop traversing, because somebody screwed up. | ||
+ | break; | ||
+ | |||
+ | case 1: // xintercept matches | ||
+ | xintercept += xstep; | ||
+ | mapy += mapystep; | ||
+ | break; | ||
+ | |||
+ | case 2: // yintercept matches | ||
+ | yintercept += ystep; | ||
+ | mapx += mapxstep; | ||
+ | break; | ||
+ | |||
+ | case 3: // xintercept and yintercept both match | ||
+ | // The trace is exiting a block through its corner. Not only does the block | ||
+ | // being entered need to be checked (which will happen when this loop | ||
+ | // continues), but the other two blocks adjacent to the corner also need to | ||
+ | // be checked. | ||
+ | if (flags & PT_ADDLINES) | ||
+ | { | ||
+ | AddLineIntercepts(mapx + mapxstep, mapy); | ||
+ | AddLineIntercepts(mapx, mapy + mapystep); | ||
+ | } | ||
+ | |||
+ | if (flags & PT_ADDTHINGS) | ||
+ | { | ||
+ | AddThingIntercepts(mapx + mapxstep, mapy, btit); | ||
+ | AddThingIntercepts(mapx, mapy + mapystep, btit); | ||
+ | } | ||
+ | xintercept += xstep; | ||
+ | yintercept += ystep; | ||
+ | mapx += mapxstep; | ||
+ | mapy += mapystep; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | In the original code, "case 3" of the switch statement was missing. Quoting [[Christoph Oelckers (Graf Zahl)]]: "When case 3 is not there the trace will get lost with no chance of ever getting back on track which would cause an endless loop. That's where the 'for' loop came in. Apparently id had problems with the code hanging but never found the real cause so they just put a safety net around their broken algorithm so that it can terminate."{{cite web|author=[[Christoph Oelckers (Graf Zahl)|Oelckers, Christoph]]|title=Is it possible to... (Heretic source)|url={{Dwforumst|id=821478}}|publication=[[Doomworld Forums]]|publishdate=12 October 2009|accessdate=15 October 2021}} | ||
+ | |||
+ | ==References== | ||
+ | <references /> | ||
[[Category:Heretic errors and bugs]] | [[Category:Heretic errors and bugs]] | ||
+ | [[Category:Hexen errors and bugs]] |
Latest revision as of 21:11, 15 October 2021
Due to buggy line of sight calculations, monsters in vanilla Heretic and Hexen may sometimes erroneously regard a player on the other side of any arbitrary number of walls as visible, causing them to wake and go into chase mode before it makes sense for them to do so. One name given to this bug is the "Anywhere Moo bug", named as such by James "Quasar" Haley who noted the bug was most readily observed with boss monsters such as the cyberdemon and maulotaur, due to their wake sounds not decreasing in volume with distance.[1]
This bug was inherited from early versions of the Doom codebase just prior to version v1.2, and persisted into Heretic, Hexen, and was notably later adapted accidentally into the ZDoom source port. It was fixed by id Software via swapping the original BLOCKMAP-based line-of-sight (LOS) checking algorithm with one based on use of the BSP tree.
Designer workaround[edit]
The most egregious cases of the bug, where monsters activate from sectors that could not possibly see the player, can be worked around by giving the map a proper REJECT table. Therefore, it is advisable for map designers who aim for vanilla compatibility to ensure that a REJECT table is built during the nodes building process.
Any remaining problems after that may, with some concession of design, be alleviated by adjusting the angle the offending monsters are facing.
Algorithmic fix[edit]
The corrected code, from ZDoom, is below:
for (count = 0 ; count < 100 ; count++) { if (flags & PT_ADDLINES) { AddLineIntercepts(mapx, mapy); } if (flags & PT_ADDTHINGS) { AddThingIntercepts(mapx, mapy, btit); } if (mapx == xt2 && mapy == yt2) { break; } // [RH] Handle corner cases properly instead of pretending they don't exist. switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx)) { case 0: // neither xintercept nor yintercept match! count = 100; // Stop traversing, because somebody screwed up. break; case 1: // xintercept matches xintercept += xstep; mapy += mapystep; break; case 2: // yintercept matches yintercept += ystep; mapx += mapxstep; break; case 3: // xintercept and yintercept both match // The trace is exiting a block through its corner. Not only does the block // being entered need to be checked (which will happen when this loop // continues), but the other two blocks adjacent to the corner also need to // be checked. if (flags & PT_ADDLINES) { AddLineIntercepts(mapx + mapxstep, mapy); AddLineIntercepts(mapx, mapy + mapystep); } if (flags & PT_ADDTHINGS) { AddThingIntercepts(mapx + mapxstep, mapy, btit); AddThingIntercepts(mapx, mapy + mapystep, btit); } xintercept += xstep; yintercept += ystep; mapx += mapxstep; mapy += mapystep; break; } }
In the original code, "case 3" of the switch statement was missing. Quoting Christoph Oelckers (Graf Zahl): "When case 3 is not there the trace will get lost with no chance of ever getting back on track which would cause an endless loop. That's where the 'for' loop came in. Apparently id had problems with the code hanging but never found the real cause so they just put a safety net around their broken algorithm so that it can terminate."[2]
References[edit]
- ↑ Haley, James (12 October 2009). "Is it possible to... (Heretic source)." Doomworld Forums. Retrieved 15 October 2021.
- ↑ Oelckers, Christoph (12 October 2009). "Is it possible to... (Heretic source)." Doomworld Forums. Retrieved 15 October 2021.