foxygit / doom Log in
commit 9e54684b11cf8e8e4ae19ebd2d754ee472c70089
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Tue Nov 30 20:00:06 2010 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Tue Nov 30 20:00:06 2010 +0000

    Add support for HACX v1.2 IWAD file.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 2176
---
 src/d_iwad.c   |  35 ++++++++++-----
 src/d_main.c   |  18 +++++++-
 src/deh_io.c   | 139 +++++++++++++++++++++++++++++++++++++++++++++++----------
 src/deh_io.h   |   1 +
 src/deh_main.c |  54 ++++++++++++++++++++--
 src/deh_main.h |   2 +
 src/doomdef.h  |   1 +
 src/m_menu.c   |   2 +
 8 files changed, 213 insertions(+), 39 deletions(-)

diff --git a/src/d_iwad.c b/src/d_iwad.c
index ea0d29d0..89a7fba3 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -326,16 +326,22 @@ static struct
     {"doom.wad",     doom},
     {"doom1.wad",    doom},
     {"chex.wad",     doom},
+    {"hacx.wad",     doom2},
 };
-
+
 // Hack for chex quest mode

-static void CheckChex(char *iwad_name)
+static void CheckSpecialIWADs(char *iwad_name)
 {
-    if (!strcmp(iwad_name, "chex.wad"))
+    if (!strcasecmp(iwad_name, "chex.wad"))
     {
         gameversion = exe_chex;
     }
+
+    if (!strcasecmp(iwad_name, "hacx.wad"))
+    {
+        gameversion = exe_hacx;
+    }
 }

 // Returns true if the specified path is a path to a file
@@ -408,7 +414,7 @@ static char *SearchDirectoryForIWAD(char *dir)

         if (filename != NULL)
         {
-            CheckChex(iwads[i].name);
+            CheckSpecialIWADs(iwads[i].name);
             gamemission = iwads[i].mission;

             return filename;
@@ -441,7 +447,7 @@ static void IdentifyIWADByName(char *name)
         if (!strcasecmp(name + strlen(name) - strlen(iwadname),
                         iwadname))
         {
-            CheckChex(iwads[i].name);
+            CheckSpecialIWADs(iwads[i].name);
             gamemission = iwads[i].mission;
             break;
         }
@@ -701,6 +707,13 @@ static char *SaveGameIWADName(void)
         return "chex.wad";
     }

+    // Hacx hack
+
+    if (gameversion == exe_hacx)
+    {
+        return "hacx.wad";
+    }
+
     // Find what subdirectory to use for savegames
     //
     // They should be stored in something like
@@ -770,6 +783,10 @@ void D_SetSaveGameDir(void)

 static char *banners[] =
 {
+    // doom2.wad
+    "                         "
+    "DOOM 2: Hell on Earth v%i.%i"
+    "                           ",
     // doom1.wad
     "                            "
     "DOOM Shareware Startup v%i.%i"
@@ -786,10 +803,6 @@ static char *banners[] =
     "                         "
     "The Ultimate DOOM Startup v%i.%i"
     "                        ",
-    // doom2.wad
-    "                         "
-    "DOOM 2: Hell on Earth v%i.%i"
-    "                           ",
     // tnt.wad
     "                     "
     "DOOM 2: TNT - Evilution v%i.%i"
@@ -809,13 +822,13 @@ static char *GetGameName(char *gamename)
 {
     size_t i;
     char *deh_sub;
-
+
     for (i=0; i<arrlen(banners); ++i)
     {
         // Has the banner been replaced?

         deh_sub = DEH_String(banners[i]);
-
+
         if (deh_sub != banners[i])
         {
             // Has been replaced
diff --git a/src/d_main.c b/src/d_main.c
index a5b38949..10eab2b0 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -660,6 +660,7 @@ static struct
     GameVersion_t version;
 } gameversions[] = {
     {"Doom 1.9",             "1.9",        exe_doom_1_9},
+    {"Hacx",                 "hacx",       exe_hacx},
     {"Ultimate Doom",        "ultimate",   exe_ultimate},
     {"Final Doom",           "final",      exe_final},
     {"Chex Quest",           "chex",       exe_chex},
@@ -711,7 +712,7 @@ static void InitGameVersion(void)
     {
         // Determine automatically

-        if (gameversion == exe_chex)
+        if (gameversion == exe_chex || gameversion == exe_hacx)
         {
             // Already determined
         }
@@ -796,6 +797,20 @@ static void LoadChexDeh(void)
     }
 }

+static void LoadHacxDeh(void)
+{
+    // If this is the HACX IWAD, we need to load the DEHACKED lump.
+
+    if (gameversion == exe_hacx)
+    {
+        if (!DEH_LoadLumpByName("DEHACKED"))
+        {
+            I_Error("DEHACKED lump not found.  Please check that this is the "
+                    "Hacx v1.2 IWAD.");
+        }
+    }
+}
+
 //
 // D_DoomMain
 //
@@ -1227,6 +1242,7 @@ void D_DoomMain (void)
     D_IdentifyVersion();
     InitGameVersion();
     LoadChexDeh();
+    LoadHacxDeh();
     D_SetGameDescription();
     D_SetSaveGameDir();

diff --git a/src/deh_io.c b/src/deh_io.c
index 3386a6fa..12fc7d56 100644
--- a/src/deh_io.c
+++ b/src/deh_io.c
@@ -30,21 +30,63 @@
 #include <string.h>

 #include "i_system.h"
+#include "w_wad.h"
 #include "z_zone.h"

 #include "deh_defs.h"
 #include "deh_io.h"

+typedef enum
+{
+    DEH_INPUT_FILE,
+    DEH_INPUT_LUMP
+} deh_input_type_t;
+
 struct deh_context_s
 {
-    FILE *stream;
+    deh_input_type_t type;
     char *filename;
+
+    // If the input comes from a memory buffer, pointer to the memory
+    // buffer.
+
+    unsigned char *input_buffer;
+    size_t input_buffer_len;
+    unsigned int input_buffer_pos;
+    int lumpnum;
+
+    // If the input comes from a file, the file stream for reading
+    // data.
+
+    FILE *stream;
+
+    // Current line number that we have reached:
+
     int linenum;
+
+    // Used by DEH_ReadLine:
+
     boolean last_was_newline;
     char *readbuffer;
     int readbuffer_size;
 };

+static deh_context_t *DEH_NewContext(void)
+{
+    deh_context_t *context;
+
+    context = Z_Malloc(sizeof(*context), PU_STATIC, NULL);
+
+    // Initial read buffer size of 128 bytes
+
+    context->readbuffer_size = 128;
+    context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL);
+    context->linenum = 0;
+    context->last_was_newline = true;
+
+    return context;
+}
+
 // Open a dehacked file for reading
 // Returns NULL if open failed

@@ -52,22 +94,41 @@ deh_context_t *DEH_OpenFile(char *filename)
 {
     FILE *fstream;
     deh_context_t *context;
-
+
     fstream = fopen(filename, "r");

     if (fstream == NULL)
         return NULL;

-    context = Z_Malloc(sizeof(*context), PU_STATIC, NULL);
+    context = DEH_NewContext();
+
+    context->type = DEH_INPUT_FILE;
     context->stream = fstream;
-
-    // Initial read buffer size of 128 bytes
+    context->filename = strdup(filename);

-    context->readbuffer_size = 128;
-    context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL);
-    context->filename = filename;
-    context->linenum = 0;
-    context->last_was_newline = true;
+    return context;
+}
+
+// Open a WAD lump for reading.
+
+deh_context_t *DEH_OpenLump(int lumpnum)
+{
+    deh_context_t *context;
+    void *lump;
+
+    lump = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+    context = DEH_NewContext();
+
+    context->type = DEH_INPUT_LUMP;
+    context->lumpnum = lumpnum;
+    context->input_buffer = lump;
+    context->input_buffer_len = W_LumpLength(lumpnum);
+    context->input_buffer_pos = 0;
+
+    context->filename = malloc(9);
+    strncpy(context->filename, lumpinfo[lumpnum].name, 8);
+    context->filename[8] = '\0';

     return context;
 }
@@ -76,33 +137,65 @@ deh_context_t *DEH_OpenFile(char *filename)

 void DEH_CloseFile(deh_context_t *context)
 {
-    fclose(context->stream);
+    if (context->type == DEH_INPUT_FILE)
+    {
+        fclose(context->stream);
+    }
+    else if (context->type == DEH_INPUT_LUMP)
+    {
+        W_ReleaseLumpNum(context->lumpnum);
+    }
+
     Z_Free(context->readbuffer);
     Z_Free(context);
 }

+int DEH_GetCharFile(deh_context_t *context)
+{
+    if (feof(context->stream))
+    {
+        // end of file
+
+        return -1;
+    }
+
+    return fgetc(context->stream);
+}
+
+int DEH_GetCharLump(deh_context_t *context)
+{
+    int result;
+
+    if (context->input_buffer_pos >= context->input_buffer_len)
+    {
+        return -1;
+    }
+
+    result = context->input_buffer[context->input_buffer_pos];
+    ++context->input_buffer_pos;
+
+    return result;
+}
+
 // Reads a single character from a dehacked file

 int DEH_GetChar(deh_context_t *context)
 {
     int result;
-
+
     // Read characters, but ignore carriage returns
     // Essentially this is a DOS->Unix conversion

-    do
+    do
     {
-        if (feof(context->stream))
+        switch (context->type)
         {
-            // end of file
+            case DEH_INPUT_FILE:
+                result = DEH_GetCharFile(context);

-            result = -1;
+            case DEH_INPUT_LUMP:
+                result = DEH_GetCharLump(context);
         }
-        else
-        {
-            result = fgetc(context->stream);
-        }
-
     } while (result == '\r');

     // Track the current line number
@@ -111,9 +204,9 @@ int DEH_GetChar(deh_context_t *context)
     {
         ++context->linenum;
     }
-
+
     context->last_was_newline = result == '\n';
-
+
     return result;
 }

diff --git a/src/deh_io.h b/src/deh_io.h
index 061a5a0e..9d22b360 100644
--- a/src/deh_io.h
+++ b/src/deh_io.h
@@ -30,6 +30,7 @@
 #include "deh_defs.h"

 deh_context_t *DEH_OpenFile(char *filename);
+deh_context_t *DEH_OpenLump(int lumpnum);
 void DEH_CloseFile(deh_context_t *context);
 int DEH_GetChar(deh_context_t *context);
 char *DEH_ReadLine(deh_context_t *context);
diff --git a/src/deh_main.c b/src/deh_main.c
index dcdfb00d..20498375 100644
--- a/src/deh_main.c
+++ b/src/deh_main.c
@@ -30,6 +30,7 @@
 #include "doomtype.h"
 #include "d_iwad.h"
 #include "m_argv.h"
+#include "w_wad.h"

 #include "deh_defs.h"
 #include "deh_io.h"
@@ -281,9 +282,6 @@ static void DEH_ParseContext(deh_context_t *context)
         DEH_Error(context, "This is not a valid dehacked patch file!");
     }

-    deh_allow_long_strings = false;
-    deh_allow_long_cheats = false;
-
     // Read the file

     for (;;)
@@ -295,7 +293,9 @@ static void DEH_ParseContext(deh_context_t *context)
         // end of file?

         if (line == NULL)
+        {
             return;
+        }

         while (line[0] != '\0' && isspace(line[0]))
             ++line;
@@ -359,6 +359,11 @@ int DEH_LoadFile(char *filename)
 {
     deh_context_t *context;

+    // Vanilla dehacked files don't allow long string or cheat replacements.
+
+    deh_allow_long_strings = false;
+    deh_allow_long_cheats = false;
+
     printf(" loading %s\n", filename);

     context = DEH_OpenFile(filename);
@@ -376,6 +381,48 @@ int DEH_LoadFile(char *filename)
     return 1;
 }

+// Load dehacked file from WAD lump.
+
+int DEH_LoadLump(int lumpnum)
+{
+    deh_context_t *context;
+
+    // If it's in a lump, it's probably designed for a modern source port,
+    // so allow it to do long string and cheat replacements.
+
+    deh_allow_long_strings = true;
+    deh_allow_long_cheats = true;
+
+    context = DEH_OpenLump(lumpnum);
+
+    if (context == NULL)
+    {
+        fprintf(stderr, "DEH_LoadFile: Unable to open lump %i\n", lumpnum);
+        return 0;
+    }
+
+    DEH_ParseContext(context);
+
+    DEH_CloseFile(context);
+
+    return 1;
+}
+
+int DEH_LoadLumpByName(char *name)
+{
+    int lumpnum;
+
+    lumpnum = W_CheckNumForName(name);
+
+    if (lumpnum == -1)
+    {
+        fprintf(stderr, "DEH_LoadLumpByName: '%s' lump not found\n", name);
+        return 0;
+    }
+
+    return DEH_LoadLump(lumpnum);
+}
+
 // Checks the command line for -deh argument

 void DEH_Init(void)
@@ -418,4 +465,3 @@ void DEH_Init(void)
     }
 }

-
diff --git a/src/deh_main.h b/src/deh_main.h
index 9248e982..4b58a1ad 100644
--- a/src/deh_main.h
+++ b/src/deh_main.h
@@ -42,6 +42,8 @@

 void DEH_Init(void);
 int DEH_LoadFile(char *filename);
+int DEH_LoadLump(int lumpnum);
+int DEH_LoadLumpByName(char *name);

 boolean DEH_ParseAssignment(char *line, char **variable_name, char **value);

diff --git a/src/doomdef.h b/src/doomdef.h
index ff4d59a9..f9cd4fd9 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -104,6 +104,7 @@ typedef enum
 typedef enum
 {
     exe_doom_1_9,   // Doom 1.9: used for shareware, registered and commercial
+    exe_hacx,       // Hacx executable (Doom 1.9 with patch applied)
     exe_ultimate,   // Ultimate Doom (retail)
     exe_final,      // Final Doom
     exe_chex,       // Chex Quest executable (based on Final Doom)
diff --git a/src/m_menu.c b/src/m_menu.c
index 5fb1ae7c..7b1c5a6e 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -784,6 +784,8 @@ void M_DrawReadThis1(void)
     switch (gameversion)
     {
         case exe_doom_1_9:
+        case exe_hacx:
+
             if (gamemode == commercial)
             {
                 // Doom 2