Doom Wiki
Advertisement
Doom Wiki


Debido a errores en los cálculos de la línea de visión, los monstruos en Vanilla Heretic y Hexen a veces pueden considerar erróneamente a un jugador al otro lado de cualquier número arbitrario de paredes como visible, lo que hace que se despierten y entren en modo persecución antes de que tenga sentido que lo hagan. El nombre dado a este error es el de "Anywhere Moo bug", nombrado así por James Quasar Haley, quien señaló que el error se observaba más fácilmente con monstruos jefes como el Ciberdemonio y el Maulotauro, debido a que sus sonidos de despertar no disminuyen de volumen con la distancia.

Este error se heredó de las primeras versiones del código fuente de Doom justo antes de la versión v1.2, y persistió en Heretic, Hexen y, notablemente, más tarde se adaptó accidentalmente en la portación de ZDoom. Fue corregido por id Software mediante el intercambio del algoritmo original de verificación de línea de visión (LOS) basado en BLOCKMAP por uno basado en el uso del árbol BSP.

Solución alternativa del diseñador[]

Los casos más atroces del error, donde los monstruos se activan desde sectores que posiblemente no podrían ver al jugador, se pueden solucionar dándole al mapa una tabla de REJECT adecuada. Por lo tanto, es aconsejable que los diseñadores de mapas que buscan compatibilidad básica se aseguren de crear una tabla REJECT durante el proceso de creación de nodos.

Cualquier problema que quede después de eso puede, con alguna concesión de diseño, aliviarse ajustando el ángulo al que se enfrentan los monstruos infractores.

Solución algorítmica[]

El código corregido de ZDoom, se encuentra a continuación:

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;
    }
  }

En el código original faltaba el "caso 3" de la declaración de cambio. Citando a Christoph Oelckers (Graf Zahl): "Cuando el caso 3 no está ahí, el rastro se perderá sin posibilidad de volver a encarrilarse, lo que provocaría un bucle sin fin. Ahí es donde entró en juego el bucle for. Aparentemente, la identificación tenía problemas con el código colgado pero nunca encontraron la causa real, así que simplemente pusieron una red de seguridad alrededor de su algoritmo roto para que pueda terminar."

Advertisement