foxygit / doom Log in
commit d610772a0b58e63f665403386f167b3e19a5dcfd
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Wed Mar 9 19:02:15 2011 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Wed Mar 9 19:02:15 2011 +0000

    Add null sector dereference emulation code from Prboom+, to fix desync
    with CLNJ-506.LMP (thanks entryway).

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 2298
---
 NEWS           |   3 ++
 src/i_system.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/i_system.h |   1 +
 src/p_map.c    |  59 ++++++++++++++++----------------
 src/p_setup.c  |  25 ++++++++++++--
 5 files changed, 162 insertions(+), 32 deletions(-)

diff --git a/NEWS b/NEWS
index 03defb19..6830685a 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,9 @@
      * Very short sound effects are not played, to better emulate the
        behavior of DMX in Vanilla Doom (thanks to Quasar for help in
        investigating this).
+     * The null sector dereference emulation code has been imported
+       from Prboom+ - this fixes a desync with CLNJ-506.LMP (thanks
+       entryway).

     Bugs fixed:
      * Menu navigation when using joystick/joypad (thanks Alexandre
diff --git a/src/i_system.c b/src/i_system.c
index 9f599192..4db97276 100644
--- a/src/i_system.c
+++ b/src/i_system.c
@@ -369,3 +369,109 @@ void I_Error (char *error, ...)
     exit(-1);
 }

+//
+// Read Access Violation emulation.
+//
+// From PrBoom+, by entryway.
+//
+
+// C:\>debug
+// -d 0:0
+//
+// DOS 6.22:
+// 0000:0000  (57 92 19 00) F4 06 70 00-(16 00)
+// DOS 7.1:
+// 0000:0000  (9E 0F C9 00) 65 04 70 00-(16 00)
+// Win98:
+// 0000:0000  (9E 0F C9 00) 65 04 70 00-(16 00)
+// DOSBox under XP:
+// 0000:0000  (00 00 00 F1) ?? ?? ?? 00-(07 00)
+
+#define DOS_MEM_DUMP_SIZE 10
+
+static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {
+  0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};
+static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {
+  0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};
+static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {
+  0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};
+static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];
+
+static const unsigned char *dos_mem_dump = mem_dump_dos622;
+
+boolean I_GetMemoryValue(unsigned int offset, void *value, int size)
+{
+    static boolean firsttime = true;
+
+    if (firsttime)
+    {
+        int p, i, val;
+
+        firsttime = false;
+        i = 0;
+
+        //!
+        // @category compat
+        // @arg <version>
+        //
+        // Specify DOS version to emulate for NULL pointer dereference
+        // emulation.  Supported versions are: dos622, dos71, dosbox.
+        // The default is to emulate DOS 7.1 (Windows 98).
+        //
+
+        p = M_CheckParmWithArgs("-setmem", 1);
+
+        if (p > 0)
+        {
+            if (!strcasecmp(myargv[p + 1], "dos622"))
+            {
+                dos_mem_dump = mem_dump_dos622;
+            }
+            if (!strcasecmp(myargv[p + 1], "dos71"))
+            {
+                dos_mem_dump = mem_dump_win98;
+            }
+            else if (!strcasecmp(myargv[p + 1], "dosbox"))
+            {
+                dos_mem_dump = mem_dump_dosbox;
+            }
+            else
+            {
+                for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i)
+                {
+                    ++p;
+
+                    if (p >= myargc || myargv[p][0] == '-')
+                    {
+                        break;
+                    }
+
+                    M_StrToInt(myargv[p], &val);
+                    mem_dump_custom[i++] = (unsigned char) val;
+                }
+
+                dos_mem_dump = mem_dump_custom;
+            }
+        }
+    }
+
+    switch (size)
+    {
+    case 1:
+        *((unsigned char *) value) = dos_mem_dump[offset];
+        return true;
+    case 2:
+        *((unsigned short *) value) = dos_mem_dump[offset]
+                                    | (dos_mem_dump[offset + 1] << 8);
+        return true;
+    case 4:
+        *((unsigned int *) value) = dos_mem_dump[offset]
+                                  | (dos_mem_dump[offset + 1] << 8)
+                                  | (dos_mem_dump[offset + 2] << 16)
+                                  | (dos_mem_dump[offset + 3] << 24);
+        return true;
+    }
+
+    return false;
+}
+
diff --git a/src/i_system.h b/src/i_system.h
index a5e06a50..06e7f662 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -86,6 +86,7 @@ void I_Tactile (int on, int off, int total);

 void I_Error (char *error, ...);

+boolean I_GetMemoryValue(unsigned int offset, void *value, int size);

 #endif

diff --git a/src/p_map.c b/src/p_map.c
index 1ac76349..cac44dd2 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -885,24 +885,16 @@ PTR_AimTraverse (intercept_t* in)

 	dist = FixedMul (attackrange, in->frac);

-        // Return false if there is no back sector.  This should never
-        // be the case if the line is two-sided; however, some WADs
-        // (eg. ottawau.wad) use this as an "impassible glass" trick
-        // and rely on Vanilla Doom's (unintentional) support for this.
-
-        if (li->backsector == NULL)
-        {
-            return false;
-        }
-
-        if (li->frontsector->floorheight != li->backsector->floorheight)
+        if (li->backsector == NULL
+         || li->frontsector->floorheight != li->backsector->floorheight)
 	{
 	    slope = FixedDiv (openbottom - shootz , dist);
 	    if (slope > bottomslope)
 		bottomslope = slope;
 	}

-	if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+	if (li->backsector == NULL
+         || li->frontsector->ceilingheight != li->backsector->ceilingheight)
 	{
 	    slope = FixedDiv (opentop - shootz , dist);
 	    if (slope < topslope)
@@ -983,26 +975,35 @@ boolean PTR_ShootTraverse (intercept_t* in)

 	dist = FixedMul (attackrange, in->frac);

-        // Check if backsector is NULL.  See comment in PTR_AimTraverse.
+        // e6y: emulation of missed back side on two-sided lines.
+        // backsector can be NULL when emulating missing back side.

-	if (li->backsector == NULL)
+        if (li->backsector == NULL)
         {
-            goto hitline;
-        }
+            slope = FixedDiv (openbottom - shootz , dist);
+            if (slope > aimslope)
+                goto hitline;

-        if (li->frontsector->floorheight != li->backsector->floorheight)
-	{
-	    slope = FixedDiv (openbottom - shootz , dist);
-	    if (slope > aimslope)
-		goto hitline;
-	}
-
-	if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
-	{
-	    slope = FixedDiv (opentop - shootz , dist);
-	    if (slope < aimslope)
-		goto hitline;
-	}
+            slope = FixedDiv (opentop - shootz , dist);
+            if (slope < aimslope)
+                goto hitline;
+        }
+        else
+        {
+            if (li->frontsector->floorheight != li->backsector->floorheight)
+            {
+                slope = FixedDiv (openbottom - shootz , dist);
+                if (slope > aimslope)
+                    goto hitline;
+            }
+
+            if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+            {
+                slope = FixedDiv (opentop - shootz , dist);
+                if (slope < aimslope)
+                    goto hitline;
+            }
+        }

 	// shot continues
 	return true;
diff --git a/src/p_setup.c b/src/p_setup.c
index 3fc95cab..e18ec81e 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -155,7 +155,24 @@ void P_LoadVertexes (int lump)
     W_ReleaseLumpNum(lump);
 }

+//
+// GetSectorAtNullAddress
+//
+sector_t* GetSectorAtNullAddress(void)
+{
+    static boolean null_sector_is_initialized = false;
+    static sector_t null_sector;
+
+    if (!null_sector_is_initialized)
+    {
+        memset(&null_sector, 0, sizeof(null_sector));
+        I_GetMemoryValue(0, &null_sector.floorheight, 4);
+        I_GetMemoryValue(4, &null_sector.ceilingheight, 4);
+        null_sector_is_initialized = true;
+    }

+    return &null_sector;
+}

 //
 // P_LoadSegs
@@ -204,10 +221,12 @@ void P_LoadSegs (int lump)

             if (sidenum < 0 || sidenum >= numsides)
             {
-                sidenum = 0;
+                li->backsector = GetSectorAtNullAddress();
+            }
+            else
+            {
+                li->backsector = sides[sidenum].sector;
             }
-
-            li->backsector = sides[sidenum].sector;
         }
         else
         {