foxygit / doom Log in
commit 052741d3485780d8e029ada086e330fdd56ee7ac
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sat Dec 23 21:24:56 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sat Dec 23 21:24:56 2006 +0000

    Add '-findiwads' command line hack so that the setup program can find
    out what games are installed. Provide a drop-down list in setup to allow
    the game type to be selected.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 803
---
 TODO                |   2 -
 setup/execute.c     |  40 +++++++-
 setup/execute.h     |   9 +-
 setup/multiplayer.c | 271 ++++++++++++++++++++++++++++++++++++++++++----------
 src/d_iwad.c        |  48 +++++++---
 src/d_iwad.h        |   1 +
 src/d_main.c        |   5 +
 7 files changed, 306 insertions(+), 70 deletions(-)

diff --git a/TODO b/TODO
index e442e5ef..74b97b86 100644
--- a/TODO
+++ b/TODO
@@ -5,8 +5,6 @@ To do:
   - Debian/Ubuntu .deb packages, Fedora .rpm packages.
   - Windows NSIS installer.
   - MacOS X .dmg packages (should be universal binaries!)
-* Smarter setup program - detect IWADs automatically and make them
-  selectable from a list.
 * Free version of the Chocolate Doom logo (from scratch, not using the
   Doom imp sprite), so t-shirts can be printed!
 * Better icon for chocolate-setup.
diff --git a/setup/execute.c b/setup/execute.c
index fb1ac722..8f60288b 100644
--- a/setup/execute.c
+++ b/setup/execute.c
@@ -26,6 +26,9 @@
 #include <stdlib.h>
 #include <string.h>

+#include <sys/types.h>
+#include <sys/wait.h>
+
 #include "textscreen.h"

 #include "configfile.h"
@@ -96,9 +99,10 @@ void AddCmdLineParameter(execute_context_t *context, char *s, ...)
     fprintf(context->stream, "\n");
 }

-void ExecuteDoom(execute_context_t *context)
+int ExecuteDoom(execute_context_t *context)
 {
     char *cmdline;
+    int result;

     fclose(context->stream);

@@ -110,13 +114,22 @@ void ExecuteDoom(execute_context_t *context)
     sprintf(cmdline, "%s @%s", DOOM_BINARY, context->response_file);

     // Run the command
-    system(cmdline);
+    result = system(cmdline);

     free(cmdline);

     // Destroy context
     remove(context->response_file);
     free(context);
+
+    if (WIFEXITED(result))
+    {
+        return WEXITSTATUS(result);
+    }
+    else
+    {
+        return -1;
+    }
 }

 static void TestCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
@@ -174,3 +187,26 @@ txt_window_action_t *TestConfigAction(void)
     return test_action;
 }

+// Invokes Doom to find which IWADs are installed.
+// This is a cheap hack to avoid duplication of the complicated install
+// path searching code inside Doom.
+
+int FindInstalledIWADs(void)
+{
+    execute_context_t *context;
+    int result;
+
+    context = NewExecuteContext();
+    AddCmdLineParameter(context, "-findiwads");
+    result = ExecuteDoom(context);
+
+    if (result < 0)
+    {
+        return 0;
+    }
+    else
+    {
+        return result;
+    }
+}
+
diff --git a/setup/execute.h b/setup/execute.h
index 8c373bf6..46301418 100644
--- a/setup/execute.h
+++ b/setup/execute.h
@@ -26,10 +26,17 @@

 typedef struct execute_context_s execute_context_t;

+#define IWAD_DOOM2    (1 << 0)       /* doom2.wad */
+#define IWAD_PLUTONIA (1 << 1)       /* plutonia.wad */
+#define IWAD_TNT      (1 << 2)       /* tnt.wad */
+#define IWAD_DOOM     (1 << 3)       /* doom.wad */
+#define IWAD_DOOM1    (1 << 4)       /* doom1.wad */
+
 execute_context_t *NewExecuteContext(void);
 void AddCmdLineParameter(execute_context_t *context, char *s, ...);
 void AddConfigParameters(execute_context_t *context);
-void ExecuteDoom(execute_context_t *context);
+int ExecuteDoom(execute_context_t *context);
+int FindInstalledIWADs(void);

 txt_window_action_t *TestConfigAction(void);

diff --git a/setup/multiplayer.c b/setup/multiplayer.c
index f55a7f8c..cd5c774b 100644
--- a/setup/multiplayer.c
+++ b/setup/multiplayer.c
@@ -34,12 +34,40 @@
 #define NUM_WADS 10
 #define NUM_EXTRA_PARAMS 10

+typedef struct
+{
+    char *filename;
+    char *description;
+    int mask;
+} iwad_t;
+
 typedef enum
 {
     WARP_DOOM1,
     WARP_DOOM2,
 } warptype_t;

+static iwad_t iwads[] =
+{
+    { "doom.wad",     "Doom",                                IWAD_DOOM },
+    { "doom2.wad",    "Doom 2",                              IWAD_DOOM2 },
+    { "tnt.wad",      "Final Doom: TNT: Evilution",          IWAD_TNT },
+    { "plutonia.wad", "Final Doom: The Plutonia Experiment", IWAD_PLUTONIA },
+    { "doom1.wad",    "Doom shareware",                      IWAD_DOOM1 },
+};
+
+// Array of IWADs found to be installed
+
+static char *found_iwads[5];
+
+// Index of the currently selected IWAD
+
+static int found_iwad_selected;
+
+// Filename to pass to '-iwad'.
+
+static char *iwadfile;
+
 static char *skills[] =
 {
     "I'm too young to die!",
@@ -78,6 +106,23 @@ static int warpmap = 1;

 static char *connect_address = NULL;

+// Find an IWAD from its description
+
+static iwad_t *GetIWADForDescription(char *description)
+{
+    int i;
+
+    for (i=0; i<sizeof(iwads) / sizeof(*iwads); ++i)
+    {
+        if (!strcmp(iwads[i].description, description))
+        {
+            return &iwads[i];;
+        }
+    }
+
+    return NULL;
+}
+
 static void AddWADs(execute_context_t *exec)
 {
     int have_wads = 0;
@@ -115,6 +160,12 @@ static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data))
     execute_context_t *exec;

     exec = NewExecuteContext();
+
+    if (iwadfile != NULL)
+    {
+        AddCmdLineParameter(exec, "-iwad %s", iwadfile);
+    }
+
     AddCmdLineParameter(exec, "-server");
     AddCmdLineParameter(exec, "-skill %i", skill + 1);

@@ -194,7 +245,6 @@ static void SetDoom1Warp(TXT_UNCAST_ARG(widget), void *val)

     l = (int) val;

-    warptype = WARP_DOOM1;
     warpepisode = l / 10;
     warpmap = l % 10;

@@ -207,7 +257,6 @@ static void SetDoom2Warp(TXT_UNCAST_ARG(widget), void *val)

     l = (int) val;

-    warptype = WARP_DOOM2;
     warpmap = l;

     UpdateWarpButton();
@@ -228,69 +277,172 @@ static void LevelSelectDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data))
     char buf[10];
     int x, y;
     int l;
+    int i;

     window = TXT_NewWindow("Select level");

-    table = TXT_NewTable(8);
+    table = TXT_NewTable(4);

     TXT_AddWidget(window, table);

-    for (y=1; y<=9; ++y)
+    if (warptype == WARP_DOOM1)
     {
-        // MAP?? levels
-
-        for (x=0; x<4; ++x)
+        // ExMy levels
+
+        for (i=0; i<4 * 9; ++i)
         {
-            l = x * 9 + y;
-
-            if (l > 32)
+            x = (i % 4) + 1;
+            y = (i / 4) + 1;
+
+            sprintf(buf, " E%iM%i ", x, y);
+            button = TXT_NewButton(buf);
+            TXT_SignalConnect(button, "pressed",
+                              SetDoom1Warp, (void *) (x * 10 + y));
+            TXT_SignalConnect(button, "pressed",
+                              CloseLevelSelectDialog, window);
+            TXT_AddWidget(table, button);
+
+            if (warpepisode == x && warpmap == y)
             {
-                TXT_AddWidget(table, NULL);
+                TXT_SelectWidget(table, button);
             }
-            else
+        }
+    }
+    else
+    {
+        for (i=0; i<32; ++i)
+        {
+            x = i % 4;
+            y = i / 4;
+
+            l = x * 8 + y + 1;
+
+            sprintf(buf, " MAP%02i ", l);
+            button = TXT_NewButton(buf);
+            TXT_SignalConnect(button, "pressed",
+                              SetDoom2Warp, (void *) l);
+            TXT_SignalConnect(button, "pressed",
+                              CloseLevelSelectDialog, window);
+            TXT_AddWidget(table, button);
+
+            if (warpmap == l)
             {
-                sprintf(buf, " MAP%02i ", l);
-                button = TXT_NewButton(buf);
-                TXT_SignalConnect(button, "pressed",
-                                  SetDoom2Warp, (void *) l);
-                TXT_SignalConnect(button, "pressed",
-                                  CloseLevelSelectDialog, window);
-                TXT_AddWidget(table, button);
-
-                if (warptype == WARP_DOOM2
-                 && warpmap == l)
-                {
-                    TXT_SelectWidget(table, button);
-                }
+                TXT_SelectWidget(table, button);
             }
         }
+    }
+}

-        // ExMy levels
-
-        for (x=1; x<=4; ++x)
+static void IWADSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
+{
+    iwad_t *iwad;
+
+    // Find the iwad_t selected
+
+    iwad = GetIWADForDescription(found_iwads[found_iwad_selected]);
+
+    // Update iwadfile
+
+    iwadfile = iwad->filename;
+}
+
+// Called when the IWAD button is changed, to update warptype.
+
+static void UpdateWarpType(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
+{
+    warptype_t new_warptype;
+    iwad_t *iwad;
+
+    // Get the selected IWAD
+
+    iwad = GetIWADForDescription(found_iwads[found_iwad_selected]);
+
+    // Find the new warp type
+
+    if (iwad->mask & (IWAD_DOOM | IWAD_DOOM1))
+    {
+        new_warptype = WARP_DOOM1;
+    }
+    else
+    {
+        new_warptype = WARP_DOOM2;
+    }
+
+    // Reset to E1M1 / MAP01 when the warp type is changed.
+
+    if (new_warptype != warptype)
+    {
+        warpepisode = 1;
+        warpmap = 1;
+    }
+
+    warptype = new_warptype;
+
+    UpdateWarpButton();
+}
+
+static txt_widget_t *IWADSelector(void)
+{
+    txt_dropdown_list_t *dropdown;
+    int installed_iwads;
+    int num_iwads;
+    int i;
+
+    // Find out what WADs are installed
+
+    installed_iwads = FindInstalledIWADs();
+
+    // Build a list of the descriptions for all installed IWADs
+
+    num_iwads = 0;
+
+    for (i=0; i<sizeof(iwads) / sizeof(*iwads); ++i)
+    {
+        if (installed_iwads & iwads[i].mask)
         {
-            if (y > 9)
-            {
-                TXT_AddWidget(table, NULL);
-            }
-            else
-            {
-                sprintf(buf, " E%iM%i ", x, y);
-                button = TXT_NewButton(buf);
-                TXT_SignalConnect(button, "pressed",
-                                  SetDoom1Warp, (void *) (x * 10 + y));
-                TXT_SignalConnect(button, "pressed",
-                                  CloseLevelSelectDialog, window);
-                TXT_AddWidget(table, button);
-
-                if (warptype == WARP_DOOM1
-                 && warpepisode == x && warpmap == y)
-                {
-                    TXT_SelectWidget(table, button);
-                }
-            }
+            found_iwads[num_iwads] = iwads[i].description;
+            ++num_iwads;
         }
     }
+
+    // Build a dropdown list of IWADs
+
+    if (num_iwads == 0)
+    {
+        // No IWAD found.  Show Doom 2 options, but this probably
+        // isn't going to work.
+
+        warptype = WARP_DOOM2;
+        warpepisode = 1;
+        warpmap = 1;
+        iwadfile = NULL;
+        UpdateWarpButton();
+
+        return (txt_widget_t *) TXT_NewLabel("Doom 2");
+    }
+    else if (num_iwads == 1)
+    {
+        // We have only one IWAD.  Show the first one as a label.
+
+        found_iwad_selected = 0;
+        IWADSelected(NULL, NULL);
+
+        return (txt_widget_t *) TXT_NewLabel(found_iwads[0]);
+    }
+    else
+    {
+        // Dropdown list allowing IWAD to be selected.
+
+        found_iwad_selected = 0;
+        IWADSelected(NULL, NULL);
+
+        dropdown = TXT_NewDropdownList(&found_iwad_selected,
+                                       found_iwads, num_iwads);
+
+        TXT_SignalConnect(dropdown, "changed", IWADSelected, NULL);
+
+        return (txt_widget_t *) dropdown;
+    }
 }

 static txt_window_action_t *StartGameAction(void)
@@ -345,6 +497,7 @@ void StartMultiGame(void)
     txt_window_t *window;
     txt_table_t *gameopt_table;
     txt_table_t *advanced_table;
+    txt_widget_t *iwad_selector;

     window = TXT_NewWindow("Start multiplayer game");

@@ -366,6 +519,8 @@ void StartMultiGame(void)
     TXT_SetColumnWidths(gameopt_table, 12, 12);

     TXT_AddWidgets(gameopt_table,
+           TXT_NewLabel("Game"),
+           iwad_selector = IWADSelector(),
            TXT_NewLabel("Skill"),
            TXT_NewDropdownList(&skill, skills, 5),
            TXT_NewLabel("Game type"),
@@ -380,11 +535,14 @@ void StartMultiGame(void)

     TXT_SetColumnWidths(advanced_table, 12, 12);

+    TXT_SignalConnect(iwad_selector, "changed", UpdateWarpType, NULL);
+
     TXT_AddWidgets(advanced_table,
                    TXT_NewLabel("UDP port"),
                    TXT_NewIntInputBox(&udpport, 5),
                    NULL);

+    UpdateWarpType(NULL, NULL);
     UpdateWarpButton();
 }

@@ -419,21 +577,30 @@ static txt_window_action_t *JoinGameAction(void)
     return action;
 }

-
 void JoinMultiGame(void)
 {
     txt_window_t *window;
+    txt_table_t *gameopt_table;

     window = TXT_NewWindow("Join multiplayer game");

     TXT_AddWidgets(window,
-        TXT_NewLabel("Connect to address: "),
-        TXT_NewInputBox(&connect_address, 40),
+        gameopt_table = TXT_NewTable(2),
         TXT_NewStrut(0, 1),
         TXT_NewButton2("Add extra parameters...", OpenExtraParamsWindow, NULL),
-        TXT_NewButton2("Add WADs...", OpenWadsWindow, NULL),
+    //    TXT_NewButton2("Add WADs...", OpenWadsWindow, NULL),
         NULL);

+    TXT_SetColumnWidths(gameopt_table, 12, 12);
+
+    TXT_AddWidgets(gameopt_table,
+                   TXT_NewLabel("Game"),
+                   IWADSelector(),
+                   TXT_NewLabel("Server address "),
+                   TXT_NewInputBox(&connect_address, 40),
+                   NULL);
+
+    TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction());
     TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, JoinGameAction());
 }

diff --git a/src/d_iwad.c b/src/d_iwad.c
index 04774203..612f2434 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -170,12 +170,12 @@ static char *GetRegistryString(registry_value_t *reg_val)

     // Allocate a buffer for the value and read the value

-    result = Z_Malloc(len, PU_STATIC, 0);
+    result = malloc(len);

     if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, (unsigned char *) result, &len)
           != ERROR_SUCCESS)
     {
-        Z_Free(result);
+        free(result);
         return NULL;
     }

@@ -209,7 +209,7 @@ static void CheckUninstallStrings(void)

         if (unstr == NULL)
         {
-            Z_Free(val);
+            free(val);
         }
         else
         {
@@ -238,17 +238,16 @@ static void CheckCollectorsEdition(void)
     for (i=0; i<sizeof(collectors_edition_subdirs)
                   / sizeof(*collectors_edition_subdirs); ++i)
     {
-        subpath = Z_Malloc(strlen(install_path)
-                           + strlen(collectors_edition_subdirs[i])
-                           + 5,
-                           PU_STATIC, 0);
+        subpath = malloc(strlen(install_path)
+                         + strlen(collectors_edition_subdirs[i])
+                         + 5);

         sprintf(subpath, "%s\\%s", install_path, collectors_edition_subdirs[i]);

         AddIWADDir(subpath);
     }

-    Z_Free(install_path);
+    free(install_path);
 }

 #endif
@@ -279,7 +278,7 @@ static char *SearchDirectoryForIWAD(char *dir)

         iwadname = DEH_String(iwads[i].name);

-        filename = Z_Malloc(strlen(dir) + strlen(iwadname) + 3, PU_STATIC, 0);
+        filename = malloc(strlen(dir) + strlen(iwadname) + 3);

         sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);

@@ -289,7 +288,7 @@ static char *SearchDirectoryForIWAD(char *dir)
             return filename;
         }

-        Z_Free(filename);
+        free(filename);
     }

     return NULL;
@@ -409,7 +408,6 @@ static void BuildIWADDirList(void)
 // Searches IWAD search paths for an IWAD with a specific name.
 //

-
 char *D_FindIWADByName(char *name)
 {
     char *buf;
@@ -429,7 +427,7 @@ char *D_FindIWADByName(char *name)
     {
         // Construct a string for the full path

-        buf = Z_Malloc(strlen(iwad_dirs[i]) + strlen(name) + 5, PU_STATIC, 0);
+        buf = malloc(strlen(iwad_dirs[i]) + strlen(name) + 5);
         sprintf(buf, "%s%c%s", iwad_dirs[i], DIR_SEPARATOR, name);

         exists = M_FileExists(buf);
@@ -439,7 +437,7 @@ char *D_FindIWADByName(char *name)
             return buf;
         }

-        Z_Free(buf);
+        free(buf);
     }

     // File not found
@@ -731,3 +729,27 @@ void D_SetGameDescription(void)
     }
 }

+// Clever hack: Setup can invoke Doom to determine which IWADs are installed.
+// Doom searches install paths and exits with the return code being a
+// bitmask of the installed IWAD files.
+
+void D_FindInstalledIWADs(void)
+{
+    int i;
+    int result;
+
+    BuildIWADDirList();
+
+    result = 0;
+
+    for (i=0; i<sizeof(iwads) / sizeof(*iwads); ++i)
+    {
+        if (D_FindIWADByName(iwads[i].name) != NULL)
+        {
+            result |= 1 << i;
+        }
+    }
+
+    exit(result);
+}
+
diff --git a/src/d_iwad.h b/src/d_iwad.h
index 404d7efb..a0f1a0ba 100644
--- a/src/d_iwad.h
+++ b/src/d_iwad.h
@@ -31,6 +31,7 @@ char *D_FindIWAD(void);
 void D_SetSaveGameDir(void);
 void D_IdentifyVersion(void);
 void D_SetGameDescription(void);
+void D_FindInstalledIWADs(void);

 #endif

diff --git a/src/d_main.c b/src/d_main.c
index a8c46a95..af892d30 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -929,6 +929,11 @@ void D_DoomMain (void)

     FindResponseFile ();

+    if (M_CheckParm("-findiwads") > 0)
+    {
+        D_FindInstalledIWADs();
+    }
+
     // print banner

     PrintBanner(PACKAGE_STRING);