home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the DOOM Programming Gurus / Tricks_of_the_Doom_Programming_Gurus.iso / bonus / editors / deth / source / deu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-02  |  31.1 KB  |  853 lines

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