home *** CD-ROM | disk | FTP | other *** search
/ Doom Fever / Doom_Fever-1995_Maple_Media.iso / wad / source.zip / DEU.C < prev    next >
C/C++ Source or Header  |  1994-05-22  |  30KB  |  918 lines

  1. /*
  2.    Doom Editor Utility, by Brendon Wyber and Raphaël Quinet.
  3.  
  4.    You are allowed to use any parts of this code in another program, as
  5.    long as you give credits to the authors in the documentation and in
  6.    the program itself.  Read the file README.1ST for more information.
  7.  
  8.    This program comes with absolutely no warranty.
  9.  
  10.    DEU.C - Main program execution routines.
  11.  
  12.    Compile with command
  13.       tcc -Z -mh -r -G -O -f -edeu *.c \tc\lib\graphics.lib
  14.  
  15.    Be sure to use the Huge memory model when you compile...
  16.  
  17. */
  18.  
  19. /* the includes */
  20. #include "deu.h"
  21. #include <time.h>
  22.  
  23. /* global variables */
  24. FILE *logfile = NULL;        /* filepointer to the error log */
  25. Bool Registered = FALSE;    /* registered or shareware game? */
  26. Bool Debug = FALSE;        /* are we debugging? */
  27. Bool SwapButtons = FALSE;    /* swap right and middle mouse buttons */
  28. Bool Quiet = FALSE;        /* don't play a sound when an object is selected */
  29. Bool Quieter = FALSE;        /* don't play any sound, even when an error occurs */
  30. Bool Expert = FALSE;        /* don't ask for confirmation for some operations */
  31. char *CfgFile = DEU_CONFIG_FILE;/* name of the configuration file */
  32. int  InitialScale = 8;        /* initial zoom factor for map */
  33. int  VideoMode = 2;        /* default video mode for VESA/SuperVGA */
  34. char *BGIDriver = "VESA";    /* default extended BGI driver */
  35. Bool FakeCursor = FALSE;    /* use a "fake" mouse cursor */
  36. Bool CirrusCursor = FALSE;    /* use hardware cursor on Cirrus Logic VGA cards */
  37. Bool Colour2 = FALSE;        /* use the alternate set for things colors */
  38. Bool InfoShown = TRUE;        /* should we display the info bar? */
  39. Bool AdditiveSelBox = FALSE;    /* additive selection box or select in box only? */
  40. int  SplitFactor = 8;        /* factor used by the Nodes builder */
  41. char *DefaultWallTexture  = "GRAY4";    /* default normal wall texture */
  42. char *DefaultUpperTexture = "ICKWALL2";    /* default upper wall texture */
  43. char *DefaultLowerTexture = "GRAY1";    /* default lower wall texture */
  44. char *DefaultFloorTexture = "FLOOR0_3";    /* default floor texture */
  45. char *DefaultCeilingTexture = "FLAT18";    /* default ceiling texture */
  46. int  DefaultFloorHeight   = 0;        /* default floor height */
  47. int  DefaultCeilingHeight = 128;    /* default ceiling height */
  48. Bool Select0 = TRUE;        /* select object 0 by default when switching modes */
  49. Bool Reminder = TRUE;        /* display a funny message when DEU starts */
  50. char *MainWad = "DOOM.WAD";    /* name of the main wad file */
  51. char **PatchWads = NULL;    /* list of patch wad files */
  52. OptDesc options[] =        /* description of the command line options */
  53. {
  54. /*   short & long names   type            message if true/changed       message if false              where to store the value */
  55.    { "d",  "debug",       OPT_BOOLEAN,    "Debug mode ON",        "Debug mode OFF",             &Debug          },
  56.    { "q",  "quiet",       OPT_BOOLEAN,    "Quiet mode ON",        "Quiet mode OFF",             &Quiet          },
  57.    { "qq", "quieter",     OPT_BOOLEAN,    "Quieter mode ON",        "Quieter mode OFF",           &Quieter        },
  58.    { "e",  "expert",      OPT_BOOLEAN,    "Expert mode ON",        "Expert mode OFF",            &Expert         },
  59.    { "sb", "swapbuttons", OPT_BOOLEAN,    "Mouse buttons swapped",    "Mouse buttons restored",     &SwapButtons    },
  60.    { "w",  "main",        OPT_STRING,     "Main WAD file",        NULL,                         &MainWad        },
  61.    { NULL, "file",        OPT_STRINGLIST, "Patch WAD file",        NULL,                         &PatchWads      },
  62.    { "pw", "pwad",        OPT_STRINGACC,  "Patch WAD file",        NULL,                         &PatchWads      },
  63.    { NULL, "config",      OPT_STRING,     "Config file",        NULL,                         &CfgFile        },
  64.    { "z",  "zoom",        OPT_INTEGER,    "Initial zoom factor",    NULL,                         &InitialScale   },
  65.    { "v",  "video",       OPT_INTEGER,    "Default video mode",        NULL,                         &VideoMode      },
  66.    { NULL, "bgi",         OPT_STRING,     "Default video driver",    NULL,                         &BGIDriver      },
  67.    { "fc", "fakecursor",  OPT_BOOLEAN,    "Fake cursor ON",        "Fake cursor OFF",            &FakeCursor     },
  68.    { "cc", "cirruscursor",OPT_BOOLEAN,    "Cirrus hardware cursor ON",    "Cirrus hardware cursor OFF", &CirrusCursor,  },
  69.    { "c",  "color2",      OPT_BOOLEAN,    "Alternate Things color set",    "Normal Things color set",    &Colour2        },
  70.    { "i",  "infobar",     OPT_BOOLEAN,    "Info bar shown",        "Info bar hidden",            &InfoShown      },
  71.    { "a",  "addselbox",   OPT_BOOLEAN,    "Additive selection box",    "Select objects in box only", &AdditiveSelBox },
  72.    { "sf", "splitfactor", OPT_INTEGER,    "Split factor",        NULL,                  &SplitFactor    },
  73.    { NULL, "walltexture", OPT_STRING,     "Default wall texture",    NULL,                         &DefaultWallTexture    },
  74.    { NULL, "lowertexture",OPT_STRING,     "Default lower wall texture",    NULL,                         &DefaultLowerTexture   },
  75.    { NULL, "uppertexture",OPT_STRING,     "Default upper wall texture",    NULL,                         &DefaultUpperTexture   },
  76.    { NULL, "floortexture",OPT_STRING,     "Default floor texture",    NULL,                         &DefaultFloorTexture   },
  77.    { NULL, "ceiltexture", OPT_STRING,     "Default ceiling texture",    NULL,                         &DefaultCeilingTexture },
  78.    { NULL, "floorheight", OPT_INTEGER,    "Default floor height",    NULL,                  &DefaultFloorHeight    },
  79.    { NULL, "ceilheight",  OPT_INTEGER,    "Default ceiling height",    NULL,                  &DefaultCeilingHeight  },
  80.    { "s0", "select0",     OPT_BOOLEAN,    "Select 0 by default",    "No default selection",          &Select0,          },
  81.    { NULL, "reminder1",   OPT_BOOLEAN,      NULL,                NULL,                  &Reminder,      },
  82.    { NULL, NULL,          OPT_END,        NULL,                NULL,                         NULL            }
  83. };
  84.  
  85.  
  86.  
  87. /*
  88.    the main program
  89. */
  90.  
  91. int main( int argc, char *argv[])
  92. {
  93.    int i;
  94.  
  95.    Credits( stdout);
  96.    argv++;
  97.    argc--;
  98.    /* InitSwap must be called before any call to GetMemory(), etc. */
  99.    InitSwap();
  100.    /* quick and dirty check for a "-config" option */
  101.    for (i = 0; i < argc - 1; i++)
  102.       if (!strcmp( argv[ i], "-config"))
  103.       {
  104.      CfgFile = argv[ i + 1];
  105.      break;
  106.       }
  107.    /* read config file and command line options */
  108.    ParseConfigFileOptions( CfgFile);
  109.    ParseCommandLineOptions( argc, argv);
  110.    if (Debug == TRUE)
  111.    {
  112.       logfile = fopen( DEU_LOG_FILE, "a");
  113.       if (logfile == NULL)
  114.      printf( "Warning: Could not open log file \"%s\"", DEU_LOG_FILE);
  115.       LogMessage(": Welcome to DEU!\n");
  116.    }
  117.    if (Quieter == TRUE)
  118.       Quiet = TRUE;
  119.    if (Reminder == TRUE)
  120.       FunnyMessage( stdout);
  121.    /* load the wad files */
  122.    OpenMainWad( MainWad);
  123.    if (PatchWads)
  124.       while (PatchWads[ 0])
  125.       {
  126.      OpenPatchWad( strupr( PatchWads[ 0]));
  127.      PatchWads++;
  128.       }
  129.    /* sanity check */
  130.    CloseUnusedWadFiles();
  131.    /* all systems go! */
  132.    MainLoop();
  133.    /* that's all, folks! */
  134.    CloseWadFiles();
  135.    LogMessage( ": The end!\n\n\n");
  136.    if (logfile != NULL)
  137.       fclose( logfile);
  138.    return 0;
  139. }
  140.  
  141.  
  142.  
  143. /*
  144.    Append a string to a null-terminated string list
  145. */
  146.  
  147. void AppendItemToList( char ***list, char *item)
  148. {
  149.    int i;
  150.  
  151.    i = 0;
  152.    if (*list != NULL)
  153.    {
  154.       /* count the number of elements in the list (last = null) */
  155.       while ((*list)[ i] != NULL)
  156.      i++;
  157.       /* expand the list */
  158.       *list = ResizeMemory( *list, (i + 2) * sizeof( char **));
  159.    }
  160.    else
  161.    {
  162.       /* create a new list */
  163.       *list = GetMemory( 2 * sizeof( char **));
  164.    }
  165.    /* append the new element */
  166.    (*list)[ i] = item;
  167.    (*list)[ i + 1] = NULL;
  168. }
  169.  
  170.  
  171.  
  172. /*
  173.    Handle command line options
  174. */
  175.  
  176. void ParseCommandLineOptions( int argc, char *argv[])
  177. {
  178.    int optnum;
  179.  
  180.    while (argc > 0)
  181.    {
  182.       if (argv[ 0][ 0] != '-' && argv[ 0][ 0] != '+')
  183.      ProgError( "options must start with '-' or '+'");
  184.       if (!strcmp( argv[ 0], "-?") || !stricmp( argv[ 0], "-h") || !stricmp( argv[ 0], "-help"))
  185.       {
  186.      Usage( stdout);
  187.      exit( 0);
  188.       }
  189.       for (optnum = 0; options[ optnum].opt_type != OPT_END; optnum++)
  190.       {
  191.      if (!stricmp( &(argv[ 0][ 1]), options[ optnum].short_name) || !stricmp( &(argv[ 0][ 1]), options[ optnum].long_name))
  192.      {
  193.         switch (options[ optnum].opt_type)
  194.         {
  195.         case OPT_BOOLEAN:
  196.            if (argv[ 0][ 0] == '-')
  197.            {
  198.           *((Bool *) (options[ optnum].data_ptr)) = TRUE;
  199.           if (options[ optnum].msg_if_true)
  200.              printf("%s.\n", options[ optnum].msg_if_true);
  201.            }
  202.            else
  203.            {
  204.           *((Bool *) (options[ optnum].data_ptr)) = FALSE;
  205.           if (options[ optnum].msg_if_false)
  206.              printf("%s.\n", options[ optnum].msg_if_false);
  207.            }
  208.            break;
  209.         case OPT_INTEGER:
  210.            if (argc <= 1)
  211.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  212.            argv++;
  213.            argc--;
  214.            *((int *) (options[ optnum].data_ptr)) = atoi( argv[ 0]);
  215.            if (options[ optnum].msg_if_true)
  216.           printf("%s: %d.\n", options[ optnum].msg_if_true, atoi( argv[ 0]));
  217.            break;
  218.         case OPT_STRING:
  219.            if (argc <= 1)
  220.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  221.            argv++;
  222.            argc--;
  223.            *((char **) (options[ optnum].data_ptr)) = argv[ 0];
  224.            if (options[ optnum].msg_if_true)
  225.           printf("%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  226.            break;
  227.         case OPT_STRINGACC:
  228.            if (argc <= 1)
  229.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  230.            argv++;
  231.            argc--;
  232.            AppendItemToList( (char ***) options[ optnum].data_ptr, argv[ 0]);
  233.            if (options[ optnum].msg_if_true)
  234.           printf("%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  235.            break;
  236.         case OPT_STRINGLIST:
  237.            if (argc <= 1)
  238.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  239.            while (argc > 1 && argv[ 1][ 0] != '-' && argv[ 1][ 0] != '+')
  240.            {
  241.           argv++;
  242.           argc--;
  243.           AppendItemToList( (char ***) options[ optnum].data_ptr, argv[ 0]);
  244.           if (options[ optnum].msg_if_true)
  245.              printf("%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  246.            }
  247.            break;
  248.         default:
  249.            ProgError( "unknown option type (BUG!)");
  250.         }
  251.         break;
  252.      }
  253.       }
  254.       if (options[ optnum].opt_type == OPT_END)
  255.      ProgError( "invalid argument: \"%s\"", argv[ 0]);
  256.       argv++;
  257.       argc--;
  258.    }
  259. }
  260.  
  261.  
  262.  
  263. /*
  264.    read the config file
  265. */
  266.  
  267. void ParseConfigFileOptions( char *filename)
  268. {
  269.    FILE *cfgfile;
  270.    char  line[ 1024];
  271.    char *value;
  272.    char *option;
  273.    char *p;
  274.    int   optnum;
  275.  
  276.    if ((cfgfile = fopen (filename, "r")) == NULL)
  277.    {
  278.       printf( "Warning: Configuration file not found (%s)\n", filename);
  279.       return;
  280.    }
  281.    while (fgets (line, 1024, cfgfile) != NULL)
  282.    {
  283.       if (line[0] == '#' || strlen( line) < 2)
  284.      continue;
  285.       if (line[ strlen( line) - 1] == '\n')
  286.      line[ strlen( line) - 1] = '\0';
  287.       /* skip blanks before the option name */
  288.       option = line;
  289.       while (isspace( option[ 0]))
  290.      option++;
  291.       /* skip the option name */
  292.       value = option;
  293.       while (value[ 0] && value[ 0] != '=' && !isspace( value[ 0]))
  294.      value++;
  295.       if (!value[ 0])
  296.      ProgError( "invalid line in %s (ends prematurely)", filename);
  297.       if (value[ 0] == '=')
  298.       {
  299.      /* mark the end of the option name */
  300.      value[ 0] = '\0';
  301.       }
  302.       else
  303.       {
  304.      /* mark the end of the option name */
  305.      value[ 0] = '\0';
  306.      value++;
  307.      /* skip blanks after the option name */
  308.      while (isspace( value[ 0]))
  309.         value++;
  310.      if (value[ 0] != '=')
  311.         ProgError( "invalid line in %s (no '=')", filename);
  312.       }
  313.       value++;
  314.       /* skip blanks after the equal sign */
  315.       while (isspace( value[ 0]))
  316.      value++;
  317.       for (optnum = 0; options[ optnum].opt_type != OPT_END; optnum++)
  318.       {
  319.      if (!stricmp( option, options[ optnum].long_name))
  320.      {
  321.         switch (options[ optnum].opt_type)
  322.         {
  323.         case OPT_BOOLEAN:
  324.            if (!stricmp(value, "yes") || !stricmp(value, "true") || !stricmp(value, "on") || !stricmp(value, "1"))
  325.            {
  326.           *((Bool *) (options[ optnum].data_ptr)) = TRUE;
  327.           if (options[ optnum].msg_if_true)
  328.              printf("%s.\n", options[ optnum].msg_if_true);
  329.            }
  330.            else if (!stricmp(value, "no") || !stricmp(value, "false") || !stricmp(value, "off") || !stricmp(value, "0"))
  331.            {
  332.           *((Bool *) (options[ optnum].data_ptr)) = FALSE;
  333.           if (options[ optnum].msg_if_false)
  334.              printf("%s.\n", options[ optnum].msg_if_false);
  335.            }
  336.            else
  337.           ProgError( "invalid value for option %s: \"%s\"", option, value);
  338.            break;
  339.         case OPT_INTEGER:
  340.            *((int *) (options[ optnum].data_ptr)) = atoi( value);
  341.            if (options[ optnum].msg_if_true)
  342.           printf("%s: %d.\n", options[ optnum].msg_if_true, atoi( value));
  343.            break;
  344.         case OPT_STRING:
  345.            p = GetMemory( (strlen( value) + 1) * sizeof( char));
  346.            strcpy( p, value);
  347.            *((char **) (options[ optnum].data_ptr)) = p;
  348.            if (options[ optnum].msg_if_true)
  349.           printf("%s: %s.\n", options[ optnum].msg_if_true, value);
  350.            break;
  351.         case OPT_STRINGACC:
  352.            p = GetMemory( (strlen( value) + 1) * sizeof( char));
  353.            strcpy( p, value);
  354.            AppendItemToList( (char ***) options[ optnum].data_ptr, p);
  355.            if (options[ optnum].msg_if_true)
  356.           printf("%s: %s.\n", options[ optnum].msg_if_true, value);
  357.            break;
  358.         case OPT_STRINGLIST:
  359.            while (value[ 0])
  360.            {
  361.           option = value;
  362.           while (option[ 0] && !isspace( option[ 0]))
  363.              option++;
  364.           option[ 0] = '\0';
  365.           option++;
  366.           while (isspace( option[ 0]))
  367.              option++;
  368.           p = GetMemory( (strlen( value) + 1) * sizeof( char));
  369.           strcpy( p, value);
  370.           AppendItemToList( (char ***) options[ optnum].data_ptr, p);
  371.           if (options[ optnum].msg_if_true)
  372.              printf("%s: %s.\n", options[ optnum].msg_if_true, value);
  373.           value = option;
  374.            }
  375.            break;
  376.         default:
  377.            ProgError( "unknown option type (BUG!)");
  378.         }
  379.         break;
  380.      }
  381.       }
  382.       if (options[ optnum].opt_type == OPT_END)
  383.      ProgError( "Invalid option in %s: \"%s\"", filename, option);
  384.    }
  385.    fclose( cfgfile);
  386. }
  387.  
  388.  
  389. /*
  390.    output the program usage to the specified file
  391. */
  392.  
  393. void Usage( FILE *where)
  394. {
  395.    fprintf( where, "Usage:\n");
  396.    fprintf( where, "DEU [-w <main_wad_file>] [-d] [-sb] [-c] [-q] [-qq] [-e] [-a] [-i] [-z <zoom>] [-bgi <driver>] [-v <mode>] [-fc] [-config <ini_file>] [-pw <pwad_file>] [-file <pwad_files>...]\n");
  397.    fprintf( where, "   -w    Gives the name of the main wad file (also -main).  Default is DOOM.WAD\n");
  398.    fprintf( where, "   -d    Enter debug mode (also -debug).\n");
  399.    fprintf( where, "   -c    Use the alternate Things color set (also -color2).\n");
  400.    fprintf( where, "   -q    Suppresses some sounds (also -quiet).\n");
  401.    fprintf( where, "   -qq   Suppresses all sounds (also -quieter).\n");
  402.    fprintf( where, "   -e    Stops prompts for confirmation (also -expert).\n");
  403.    fprintf( where, "   -a    To have an additive selection box (also -addselbox).\n");
  404.    fprintf( where, "   -i    Show the info bar in the editors (also -infobar).\n");
  405.    fprintf( where, "   -z    Set the initial zoom factor for the editors (also -zoom).\n");
  406.    fprintf( where, "   -v    Set the default video mode number (also -video).\n");
  407.    fprintf( where, "   -bgi  Set the default video driver (*.BGI file).\n");
  408.    fprintf( where, "   -fc   Use a \"fake\" mouse cursor (also -fakecursor).\n");
  409.    fprintf( where, "   -sb   Swaps the mouse buttons (also -swapbuttons).\n");
  410.    fprintf( where, "   -pw   To add one patch wad file to be loaded; may be repeated (also -pwad).\n");
  411.    fprintf( where, "   -file To add a list of patch wad files to be loaded.\n");
  412.    fprintf( where, "   -config Gives the name of the config file.\n");
  413.    fprintf( where, "Put a '+' instead of a '-' before boolean options to reverse their effect.\n");
  414. }
  415.  
  416.  
  417.  
  418. /*
  419.    output the credits of the program to the specified file
  420. */
  421.  
  422. void Credits( FILE *where)
  423. {
  424.    fprintf( where, "\nDEU: Doom Editor Utilities, ver %s.\n", DEU_VERSION);
  425.    fprintf( where, " By Raphaël Quinet (quinet@montefiore.ulg.ac.be),\n");
  426.    fprintf( where, "and Brendon J Wyber (b.wyber@csc.canterbury.ac.nz).\n\n");
  427. }
  428.  
  429.  
  430.  
  431. /*
  432.    display a funny message on the screen
  433. */
  434.  
  435. void FunnyMessage( FILE *where)
  436. {
  437.    fprintf( where, "\n");
  438.    fprintf( where, "*----------------------------------------------------------------------------*\n");
  439.    fprintf( where, "| Welcome to DEU!  This is a poweful utility and, like all good tools, it    |\n");
  440.    fprintf( where, "| comes with its user's manual.  Please print and read DEU.TXT if you want   |\n");
  441.    fprintf( where, "| to discover all the features of this program.  If you are new to DEU, the  |\n");
  442.    fprintf( where, "| tutorial will show you how to build your first level.                      |\n");
  443.    fprintf( where, "|                                                                            |\n");
  444.    fprintf( where, "| If you are an experienced DEU user and want to know what has changed since |\n");
  445.    fprintf( where, "| the last version, you should read the revision history in README.1ST.      |\n");
  446.    fprintf( where, "|                                                                            |\n");
  447.    fprintf( where, "| And if you have lots of suggestions for improvements, bug reports, or even |\n");
  448.    fprintf( where, "| complaints about this program, be sure to read README.1ST first.           |\n");
  449.    fprintf( where, "| Hint: you can easily disable this message.  Read the docs carefully...     |\n");
  450.    fprintf( where, "*----------------------------------------------------------------------------*\n");
  451. }
  452.  
  453.  
  454. /*
  455.    play a fascinating tune
  456. */
  457.  
  458. void Beep()
  459. {
  460.    if (Quieter == FALSE)
  461.    {
  462.       sound( 640);
  463.       delay( 100);
  464.       nosound();
  465.    }
  466. }
  467.  
  468.  
  469.  
  470. /*
  471.    play a sound
  472. */
  473.  
  474. void PlaySound( int freq, int msec)
  475. {
  476.    if (Quiet == FALSE)
  477.    {
  478.       sound( freq);
  479.       delay( msec);
  480.       nosound();
  481.    }
  482. }
  483.  
  484.  
  485.  
  486. /*
  487.    terminate the program reporting an error
  488. */
  489.  
  490. void ProgError( char *errstr, ...)
  491. {
  492.    va_list args;
  493.  
  494.    Beep();
  495.    Beep();
  496.    if (GfxMode)
  497.    {
  498.       sleep( 1);
  499.       TermGfx();
  500.    }
  501.    va_start( args, errstr);
  502.    printf( "\nProgram Error: *** ");
  503.    vprintf( errstr, args);
  504.    printf( " ***\n");
  505.    if (Debug == TRUE && logfile != NULL)
  506.    {
  507.       fprintf( logfile, "\nProgram Error: *** ");
  508.       vfprintf( logfile, errstr, args);
  509.       fprintf( logfile, " ***\n");
  510.    }
  511.    va_end( args);
  512.    /* clean up things and free swap space */
  513.    ForgetLevelData();
  514.    ForgetWTextureNames();
  515.    ForgetFTextureNames();
  516.    CloseWadFiles();
  517.    exit( 5);
  518. }
  519.  
  520.  
  521.  
  522. /*
  523.    write a message in the log file
  524. */
  525.  
  526. void LogMessage( char *logstr, ...)
  527. {
  528.    va_list  args;
  529.    time_t   tval;
  530.    char    *tstr;
  531.  
  532.    if (Debug == TRUE && logfile != NULL)
  533.    {
  534.       va_start( args, logstr);
  535.       /* if the messsage begins with ":", output the current date & time first */
  536.       if (logstr[ 0] == ':')
  537.       {
  538.      time( &tval);
  539.      tstr = ctime( &tval);
  540.      tstr[ strlen( tstr) - 1] = '\0';
  541.      fprintf(logfile, "%s", tstr);
  542.       }
  543.       vfprintf( logfile, logstr, args);
  544.       va_end( args);
  545.    }
  546. }
  547.  
  548.  
  549.  
  550. /*
  551.    the main program menu loop
  552. */
  553.  
  554. void MainLoop()
  555. {
  556.    char input[ 120];
  557.    char *com, *out;
  558.    FILE *file, *raw;
  559.    WadPtr wad;
  560.    int episode, level;
  561.  
  562.    for (;;)
  563.    {
  564.       /* get the input */
  565.       printf( "\n[? for help]> ");
  566.       gets( input);
  567.       printf( "\n");
  568.       strupr( input);
  569.  
  570.       /* eat the white space and get the first command word */
  571.       com = strtok( input, " ");
  572.  
  573.       /* user just hit return */
  574.       if (com == NULL)
  575.      printf( "[Please enter a command or ? for help.]\n");
  576.  
  577.       /* user inputting for help */
  578.       else if (!strcmp( com, "?"))
  579.       {
  580.      printf( "?                                 -- to display this text\n");
  581.      printf( "B[uild] <WadFile>                 -- to build a new main WAD file\n");
  582.      printf( "C[reate] [episode [level]]        -- to create and edit a new (empty) level\n");
  583.      printf( "D[ump] <DirEntry> [outfile]       -- to dump a directory entry in hex\n");
  584.      printf( "E[dit] [episode [level]]          -- to edit a game level saving results to\n");
  585.      printf( "                                          a patch wad file\n");
  586.      printf( "G[roup] <WadFile>                 -- to group all patch wads in a file\n");
  587.      printf( "I[nsert] <RawFile> <DirEntry>     -- to insert a raw file in a patch wad file\n");
  588.      printf( "L[ist] <WadFile> [outfile]        -- to list the directory of a wadfile\n");
  589.      printf( "M[aster] [outfile]                -- to list the master directory\n");
  590.      printf( "Q[uit]                            -- to quit\n");
  591.      printf( "R[ead] <WadFile>                  -- to read a new wad patch file\n");
  592.      printf( "S[ave] <DirEntry> <WadFile>       -- to save one object to a separate file\n");
  593.      printf( "V[iew] [SpriteName]               -- to display the sprites\n");
  594.      printf( "W[ads]                            -- to display the open wads\n");
  595.      printf( "X[tract] <DirEntry> <RawFile>     -- to save (extract) one object to a raw file\n");
  596.       }
  597.  
  598.       /* user asked for list of open WAD files */
  599.       else if (!strcmp( com, "WADS") || !strcmp( com, "W"))
  600.       {
  601.      printf( "%-20s  IWAD  (Main wad file)\n", WadFileList->filename);
  602.      for (wad = WadFileList->next; wad; wad = wad->next)
  603.      {
  604.         if (wad->directory[ 0].name[ 0] == 'E' && wad->directory[ 0].name[ 2] == 'M')
  605.            printf( "%-20s  PWAD  (Patch wad file for episode %c level %c)\n", wad->filename, wad->directory[ 0].name[ 1], wad->directory[ 0].name[ 3]);
  606.         else
  607.         {
  608.            /* kluge */
  609.            strncpy( input, wad->directory[ 0].name, 8);
  610.            input[ 8] = '\0';
  611.            printf( "%-20s  PWAD  (Patch wad file for %s)\n", wad->filename, input);
  612.         }
  613.      }
  614.       }
  615.  
  616.       /* user asked to quit */
  617.       else if (!strcmp( com, "QUIT") || !strcmp( com, "Q"))
  618.       {
  619.      if (! Registered)
  620.         printf("Remember to register your copy of DOOM!\n");
  621.      printf( "Goodbye...\n");
  622.      break;
  623.       }
  624.  
  625.       /* user asked to edit a level */
  626.       else if (!strcmp( com, "EDIT") || !strcmp( com, "E") || !strcmp( com, "CREATE") || !strcmp( com, "C"))
  627.       {
  628.      episode = 0;
  629.      level = 0;
  630.      com = strtok( NULL, " ");
  631.      if (com != NULL)
  632.      {
  633.         episode = atoi( com);
  634.         if (episode < 1 || episode > 3)
  635.         {
  636.            printf( "[Invalid game episode number (%s).]\n", com);
  637.            continue;
  638.         }
  639.         com = strtok( NULL, " ");
  640.         if (com != NULL)
  641.         {
  642.            level = atoi( com);
  643.            if (level < 1 || level> 9)
  644.            {
  645.           printf( "[Invalid game level number (%s).]\n", com);
  646.           continue;
  647.            }
  648.         }
  649.      }
  650.      com = strtok( input, " ");
  651.      EditLevel( episode, level, !strcmp( com, "CREATE") || !strcmp( com, "C"));
  652.       }
  653.  
  654.       /* user asked to build a new main WAD file */
  655.       else if (!strcmp( com, "BUILD") || !strcmp( com, "B"))
  656.       {
  657.      com = strtok( NULL, " ");
  658.      if (com == NULL)
  659.      {
  660.         printf( "[Wad file name argument missing.]\n");
  661.         continue;
  662.      }
  663.      for (wad = WadFileList; wad; wad = wad->next)
  664.         if (!stricmp( com, wad->filename))
  665.            break;
  666.      if (wad)
  667.      {
  668.         printf( "[File \"%s\" is opened and cannot be overwritten.]\n", com);
  669.         continue;
  670.      }
  671.      BuildNewMainWad( com, FALSE);
  672.       }
  673.  
  674.       /* user asked to build a compound patch WAD file */
  675.       else if (!strcmp( com, "GROUP") || !strcmp( com, "G"))
  676.       {
  677.      if (WadFileList->next == NULL || WadFileList->next->next == NULL)
  678.      {
  679.         printf( "[You need at least two open wad files if you want to group them.]\n");
  680.         continue;
  681.      }
  682.      com = strtok( NULL, " ");
  683.      if (com == NULL)
  684.      {
  685.         printf( "[Wad file name argument missing.]\n");
  686.         continue;
  687.      }
  688.      for (wad = WadFileList; wad; wad = wad->next)
  689.         if (!stricmp( com, wad->filename))
  690.            break;
  691.      if (wad)
  692.      {
  693.         printf( "[File \"%s\" is opened and cannot be overwritten.]\n", com);
  694.         continue;
  695.      }
  696.      BuildNewMainWad( com, TRUE);
  697.       }
  698.  
  699.       /* user ask for a listing of a WAD file */
  700.       else if (!strcmp( com, "LIST") || !strcmp( com, "L"))
  701.       {
  702.      com = strtok( NULL, " ");
  703.      if (com == NULL)
  704.      {
  705.         printf( "[Wad file name argument missing.]\n");
  706.         continue;
  707.      }
  708.      for (wad = WadFileList; wad; wad = wad->next)
  709.         if (!stricmp( com, wad->filename))
  710.            break;
  711.      if (wad == NULL)
  712.      {
  713.         printf( "[Wad file \"%s\" is not open.]\n", com);
  714.         continue;
  715.      }
  716.      out = strtok( NULL, " ");
  717.      if (out)
  718.      {
  719.         printf( "Outputting directory of \"%s\" to \"%s\".\n", wad->filename, out);
  720.         if ((file = fopen( out, "wt")) == NULL)
  721.            ProgError( "error opening output file \"%s\"", com);
  722.         Credits( file);
  723.         ListFileDirectory( file, wad);
  724.         fprintf( file, "\nEnd of file.\n");
  725.         fclose( file);
  726.      }
  727.      else
  728.         ListFileDirectory( stdout, wad);
  729.       }
  730.  
  731.       /* user asked for the list of the master directory */
  732.       else if (!strcmp( com, "MASTER") || !strcmp( com, "M"))
  733.       {
  734.      out = strtok( NULL, " ");
  735.      if (out)
  736.      {
  737.         printf( "Outputting master directory to \"%s\".\n", out);
  738.         if ((file = fopen( out, "wt")) == NULL)
  739.            ProgError( "error opening output file \"%s\"", com);
  740.         Credits( file);
  741.         ListMasterDirectory( file);
  742.         fprintf( file, "\nEnd of file.\n");
  743.         fclose( file);
  744.      }
  745.      else
  746.         ListMasterDirectory( stdout);
  747.       }
  748.  
  749.       /* user asked to read a new patch WAD file */
  750.       else if (!strcmp( com, "READ") || !strcmp( com, "R"))
  751.       {
  752.      com = strtok( NULL, " ");
  753.      if (com == NULL)
  754.      {
  755.         printf( "[Wad file name argument missing.]\n");
  756.         continue;
  757.      }
  758.      out = strtok( NULL, " ");
  759.      if (out)
  760.        *out = '\0';
  761.      out = GetMemory( (strlen( com) + 1) * sizeof( char));
  762.      strcpy( out, com);
  763.      OpenPatchWad( out);
  764.      CloseUnusedWadFiles();
  765.       }
  766.  
  767.       /* user asked to dump the contents of a WAD file */
  768.       else if (!strcmp( com, "DUMP") || !strcmp( com, "D"))
  769.       {
  770.      com = strtok( NULL, " ");
  771.      if (com == NULL)
  772.      {
  773.         printf( "[Object name argument missing.]\n");
  774.         continue;
  775.      }
  776.      out = strtok( NULL, " ");
  777.      if (out)
  778.      {
  779.         printf( "Outputting directory entry data to \"%s\".\n", out);
  780.         if ((file = fopen( out, "wt")) == NULL)
  781.            ProgError( "error opening output file \"%s\"", com);
  782.         Credits( file);
  783.         DumpDirectoryEntry( file, com);
  784.         fprintf( file, "\nEnd of file.\n");
  785.         fclose( file);
  786.      }
  787.      else
  788.         DumpDirectoryEntry( stdout, com);
  789.       }
  790.  
  791.       /* user asked to view the sprites */
  792.       else if (!strcmp( com, "VIEW") || !strcmp( com, "V"))
  793.       {
  794.      InitGfx();
  795.      com = strtok( NULL, " ");
  796.      ChooseSprite( -1, -1, "Sprite viewer", com);
  797.      TermGfx();
  798.       }
  799.  
  800.       /* user asked to save an object to a separate PWAD file */
  801.       else if (!strcmp( com, "SAVE") || !strcmp( com, "S"))
  802.       {
  803.      com = strtok( NULL, " ");
  804.      if (com == NULL)
  805.      {
  806.         printf( "[Object name argument missing.]\n");
  807.         continue;
  808.      }
  809.      if (strlen( com) > 8 || strchr( com, '.') != NULL)
  810.      {
  811.         printf( "[Invalid object name.]\n");
  812.         continue;
  813.      }
  814.      out = strtok( NULL, " ");
  815.      if (out == NULL)
  816.      {
  817.         printf( "[Wad file name argument missing.]\n");
  818.         continue;
  819.      }
  820.      for (wad = WadFileList; wad; wad = wad->next)
  821.         if (!stricmp( out, wad->filename))
  822.            break;
  823.      if (wad)
  824.      {
  825.         printf( "[This Wad file is already in use.  You may not overwrite it.]\n");
  826.         continue;
  827.      }
  828.      printf( "Saving directory entry data to \"%s\".\n", out);
  829.      if ((file = fopen( out, "wb")) == NULL)
  830.         ProgError( "error opening output file \"%s\"", out);
  831.      SaveDirectoryEntry( file, com);
  832.      fclose( file);
  833.       }
  834.  
  835.       /* user asked to encapsulate a raw file in a PWAD file */
  836.       else if (!strcmp( com, "INSERT") || !strcmp( com, "I"))
  837.       {
  838.      com = strtok( NULL, " ");
  839.      if (com == NULL)
  840.      {
  841.         printf( "[Raw file name argument missing.]\n");
  842.         continue;
  843.      }
  844.      out = strtok( NULL, " ");
  845.      if (out == NULL)
  846.      {
  847.         printf( "[Object name argument missing.]\n");
  848.         continue;
  849.      }
  850.      if (strlen( out) > 8 || strchr( out, '.') != NULL)
  851.      {
  852.         printf( "[Invalid object name.]\n");
  853.         continue;
  854.      }
  855.      if ((raw = fopen( com, "rb")) == NULL)
  856.         ProgError( "error opening input file \"%s\"", com);
  857.      /* kluge */
  858.      strcpy( input, out);
  859.      strcat( input, ".WAD");
  860.      for (wad = WadFileList; wad; wad = wad->next)
  861.         if (!stricmp( input, wad->filename))
  862.            break;
  863.      if (wad)
  864.      {
  865.         printf( "[This Wad file is already in use (%s).  You may not overwrite it.]\n", input);
  866.         continue;
  867.      }
  868.      printf( "Including new object %s in \"%s\".\n", out, input);
  869.      if ((file = fopen( input, "wb")) == NULL)
  870.         ProgError( "error opening output file \"%s\"", input);
  871.      SaveEntryFromRawFile( file, raw, out);
  872.      fclose( raw);
  873.      fclose( file);
  874.       }
  875.  
  876.       /* user asked to extract an object to a raw binary file */
  877.       else if (!strcmp( com, "XTRACT") || !strcmp( com, "EXTRACT") || !strcmp( com, "X"))
  878.       {
  879.      com = strtok( NULL, " ");
  880.      if (com == NULL)
  881.      {
  882.         printf( "[Object name argument missing.]\n");
  883.         continue;
  884.      }
  885.      if (strlen( com) > 8 || strchr( com, '.') != NULL)
  886.      {
  887.         printf( "[Invalid object name.]\n");
  888.         continue;
  889.      }
  890.      out = strtok( NULL, " ");
  891.      if (out == NULL)
  892.      {
  893.         printf( "[Raw file name argument missing.]\n");
  894.         continue;
  895.      }
  896.      for (wad = WadFileList; wad; wad = wad->next)
  897.         if (!stricmp( out, wad->filename))
  898.            break;
  899.      if (wad)
  900.      {
  901.         printf( "[You may not overwrite an opened Wad file with raw data.]\n");
  902.         continue;
  903.      }
  904.      printf( "Saving directory entry data to \"%s\".\n", out);
  905.      if ((file = fopen( out, "wb")) == NULL)
  906.         ProgError( "error opening output file \"%s\"", out);
  907.      SaveEntryToRawFile( file, com);
  908.      fclose( file);
  909.       }
  910.  
  911.       /* unknown command */
  912.       else
  913.      printf( "[Unknown command \"%s\"!]\n", com);
  914.    }
  915. }
  916.  
  917. /* end of file */
  918.