home *** CD-ROM | disk | FTP | other *** search
/ FMI Superhry 1 / Superhry-I.bin / bonus / doom / programs / wadwha11 / wadwhat.c < prev    next >
C/C++ Source or Header  |  1994-08-29  |  27KB  |  819 lines

  1. /*
  2.  * WADWHAT.C - print the contents of a DOOM WAD file
  3.  *
  4.  * by Randall R. Spangler
  5.  *
  6.  * Version 1.1, released 8/28/94
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <dos.h>
  15. #include <dir.h>
  16.  
  17. struct s_thing {                /* Thing data */
  18.     short int   x, y;           /* Coordinates */
  19.     short int   facing;         /* Facing, in degrees */
  20.     short int   type;           /* Type of thing */
  21.     short int   attr;           /* Thing attributes */
  22. };
  23. typedef struct s_thing THING;
  24.  
  25. /***************************************************************************/
  26.  
  27. char        contents[10][9] =   /* Valid sub-entry names for a level */
  28. {"THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS",
  29. "NODES", "SECTORS", "REJECT", "BLOCKMAP"};
  30.  
  31. char        itemline[] = "\t%-20s %5ld %5ld %5ld %5ld + %5d %5d %5d %5d\n";     /* Line of text for an
  32.                                                                                  * item */
  33.  
  34. /***************************************************************************/
  35.  
  36. int         isbrief = 0;        /* If non-zero, is the skill level we're
  37.                                  * printing brief stats on */
  38. int         battr = 0;          /* Matching attribute byte for brief printout */
  39.  
  40. int         battrarry[5] = {0x01, 0x01, 0x02, 0x04, 0x04};      /* Attribute bytes vs.
  41.                                                                  * skill level */
  42.  
  43. FILE       *savefile;           /* WAD file whose things we're looking at */
  44. long        savefilepos;        /* Save position in WAD file (where we were
  45.                                  * before we started looking at THINGS,
  46.                                  * LINEDEFS, or SECTORS) */
  47.  
  48. long        thoff = 0, thlen = 0;       /* Position and length of thing data */
  49. long        ldoff = 0, ldlen = 0;       /* Position and length of linedef
  50.                                          * data */
  51. long        seoff = 0, selen = 0;       /* Position and length of sector data */
  52. long        rjlen = 0;          /* Length of reject data */
  53.  
  54. THING      *th;                 /* Thing data for a level */
  55. int         numth = 0;          /* Number of things */
  56.  
  57. char        buf[256];
  58.  
  59. /***************************************************************************/
  60.  
  61. long        countth(int type, int attr)
  62. {
  63.     /* Returns the number of things of the specified type with at least one
  64.      * matching attribute bit.  If the multi-player bit in <attr> is on,
  65.      * matches either single or multi-player; else matches single-player
  66.      * only. <attr>=(-1) matches any skill or multi-player. */
  67.  
  68.     THING      *t = th;         /* Current thing */
  69.  
  70.     int         askill = attr & 0x07;   /* Skill bits of attribute */
  71.     int         amp = attr & 0x10;      /* Multi-player bits of attribute */
  72.  
  73.     long        n = 0;          /* Number of matches */
  74.     int         i;
  75.  
  76.     for (i = 0; i < numth; i++, t++) {  /* Search all things */
  77.         if (t->type != type)
  78.             continue;                   /* Wrong object */
  79.  
  80.         if (attr < 0)
  81.             n++;                        /* Match all objects of this type */
  82.         else if (t->attr & askill) {
  83.             if (amp)
  84.                 n++;                    /* Want single or multi */
  85.             else if (!(t->attr & 0x10))
  86.                 n++;                    /* Want single only */
  87.         }
  88.     }
  89.  
  90.     return n;                           /* Return match count */
  91. }
  92.  
  93. /***************************************************************************/
  94.  
  95. long       *countdiff(int type, long *dest)
  96. {
  97.     /* Counts the number of things of the specified type at each difficulty
  98.      * level.  dest[0]=L12, dest[1]=L3, dest[2]=L45, dest[3]=multiplayer
  99.      * only. Returns a pointer to the destination array, or NULL if error. */
  100.  
  101.     THING      *t = th;
  102.     int         i;
  103.  
  104.     for (i = 0; i < 6; i++)
  105.         dest[i] = 0;                    /* Clear destination array */
  106.  
  107.     for (i = 0; i < numth; i++) {       /* Search all things */
  108.         if (t->type == type) {          /* Matched type */
  109.             if (t->attr & 0x00010) {    /* Multi-player only */
  110.                 if (t->attr & 0x0001)
  111.                     dest[3]++;
  112.                 if (t->attr & 0x0002)
  113.                     dest[4]++;
  114.                 if (t->attr & 0x0004)
  115.                     dest[5]++;
  116.             } else {                    /* Single-player only */
  117.                 if (t->attr & 0x0001)
  118.                     dest[0]++;
  119.                 if (t->attr & 0x0002)
  120.                     dest[1]++;
  121.                 if (t->attr & 0x0004)
  122.                     dest[2]++;
  123.             }
  124.         }
  125.         t++;                            /* Advance to next thing */
  126.     }
  127.  
  128.     for (i = 0; i < 3; i++)
  129.         dest[i + 3] += dest[i];         /* Single-player stuff is present in
  130.                                          * multi-player too */
  131.  
  132.     return dest;                        /* Return match count */
  133. }
  134.  
  135. /***************************************************************************/
  136.  
  137. long       *addcountweighted(int type, long *dest, int weight)
  138. {
  139.     /* Similar to countdiff(), but adds <weight> times the counts vs.
  140.      * difficulty to the destination array instead of just setting it to the
  141.      * match counts. Returns NULL if error. */
  142.  
  143.     long        nd[6];
  144.     int         i;
  145.  
  146.     countdiff(type, nd);                /* Count the matches */
  147.  
  148.     for (i = 0; i < 6; i++)
  149.         dest[i] += weight * nd[i];      /* Add a weighted result */
  150.  
  151.     return dest;
  152. }
  153.  
  154. /***************************************************************************/
  155. /***************************************************************************/
  156.  
  157. int         loadthings(FILE * f, long offs, long len)
  158. {
  159.     /* Loads a map's THINGS data at offset <offs>, length <len>.  Returns
  160.      * zero if error. */
  161.  
  162.     savefile = f;               /* Save WAD file handle */
  163.     savefilepos = ftell(f);             /* Save position in WAD file */
  164.  
  165.     fseek(f, offs, SEEK_SET);
  166.     th = (THING *) malloc(len);
  167.     if (!th) {
  168.         fprintf(stderr, "Not enough memory to hold THINGS\n");
  169.         return 0;
  170.     }
  171.     fread(th, 1, len, f);
  172.     numth = len / 10;
  173.  
  174.     return 1;                           /* Success */
  175. }
  176.  
  177. int         freethings(void)
  178. {
  179.     /* Frees a map's THINGS data loaded by loadthings().  Returns zero if
  180.      * error. */
  181.  
  182.     free(th);
  183.     numth = 0;
  184.  
  185.     fseek(savefile, savefilepos, SEEK_SET);
  186.  
  187.     return 1;                           /* Success */
  188. }
  189.  
  190. /***************************************************************************/
  191.  
  192. void        printitem(char *desc, long *arry, int double1)
  193. {
  194.     /* Prints an item's presence at all skill levels.  If double1, doubles
  195.      * the numbers in columns 1 and 5.  */
  196.  
  197.     int         i;
  198.  
  199.     for (i = 0; i < 6; i++)
  200.         if (arry[i])
  201.             break;
  202.  
  203.     if (i == 6)
  204.         return;                         /* Item is not present at any skill
  205.                                          * level */
  206.  
  207.     printf("\t%-20.20s", desc);         /* Print description */
  208.  
  209.     for (i = 0; i < 6; i++) {
  210.         if (i == 3)
  211.             printf(" |");
  212.         if (i == 0 || i == 3)
  213.             printf(" %5ld", (double1 ? 2 * arry[i] : arry[i]));
  214.         printf(" %5ld", arry[i]);
  215.     }
  216.     printf("\n");
  217. }
  218.  
  219.  
  220. /***************************************************************************/
  221.  
  222. void        prtth(int type, char *desc)
  223. {
  224.     /* Prints the description and number of matching things at each
  225.      * difficulty level. */
  226.  
  227.     long        nd[6] = {0, 0, 0, 0, 0, 0};     /* Numbers at each difficulty
  228.                                                  * level */
  229.  
  230.     countdiff(type, nd);
  231.     printitem(desc, nd, 0);
  232. }
  233.  
  234. /***************************************************************************/
  235.  
  236. /* If there is at least one thing with id <no>, print the description of the
  237.  * thing and the number present at each skill level. */
  238. #define PRINTITEM(desc,arry) printitem(desc,arry,0)
  239. #define PRINTITEM2(desc,arry) printitem(desc,arry,1)
  240.  
  241. /* Reset an array */
  242. #define RESET(arry) for(i=0; i<6; i++) arry[i]=0
  243.  
  244. int         countthings(void)
  245. {
  246.     /* Counts the things in a level's THINGS data.  Returns zero if error. */
  247.  
  248.     long        nc[6] = {0, 0, 0, 0, 0, 0};     /* Number of things counted
  249.                                                  * at each skill level */
  250.     long        wdam[6] = {0, 0, 0, 0, 0, 0};   /* Total weapon damage at
  251.                                                  * each skill level */
  252.     float       dratio[6] = {0, 0, 0, 0, 0, 0}; /* Damage ratio for
  253.                                                  * difficulty */
  254.     int         n, i;
  255.  
  256.     /** Player starts **/
  257.  
  258.     printf("    Play modes:\n");
  259.  
  260.     if (countth(1, -1))                 /* Find player 1 start */
  261.         printf("\tSingle player\n");
  262.     n = 0;
  263.  
  264.     for (i = 1; i <= 4; i++) {          /* Find player 1-4 starts */
  265.         if (countth(i, -1))
  266.             n++;
  267.     }
  268.     if (n > 1)
  269.         printf("\tCooperative (%d player)\n", n);
  270.  
  271.     n = countth(11, -1);                /* Find deathmatch starts */
  272.     if (n)
  273.         printf("\tDeathmatch (%d starts)\n", n);
  274.  
  275.     /** Monsters **/
  276.  
  277.     printf("    Bosses:\n");
  278.     prtth(3003, "Baron");
  279.     prtth(16, "Cyberdemon");
  280.     prtth(7, "Spiderdemon");
  281.  
  282.     printf("    Monsters:\n");
  283.     prtth(3004, "Trooper");
  284.     prtth(9, "Sergeant");
  285.     prtth(3001, "Imp");
  286.     prtth(3002, "Demon");
  287.     prtth(58, "Spectre");
  288.     prtth(3006, "Lost soul");
  289.     prtth(3005, "Cacodemon");
  290.  
  291.     printf("    Weapons:\n");
  292.     prtth(2001, "Shotgun");
  293.     prtth(2002, "Chaingun");
  294.     prtth(2003, "Rocket launcher");
  295.     prtth(2004, "Plasma gun");
  296.     prtth(2006, "BFG-9000");
  297.     prtth(2005, "Chainsaw");
  298.  
  299.     printf("    Equipment:\n");
  300.     prtth(8, "Backpack");
  301.     prtth(2022, "Invulnerability");
  302.     prtth(2023, "Berserk");
  303.     prtth(2024, "Invisibility");
  304.     prtth(2025, "Radiation suit");
  305.     prtth(2026, "Computer map");
  306.     prtth(2045, "Lite amp goggles");
  307.  
  308.     printf("    Expendibles:\n");
  309.  
  310.     RESET(nc);
  311.     addcountweighted(2002, nc, 20);     /* Chainguns */
  312.     addcountweighted(2007, nc, 10);     /* Clips */
  313.     addcountweighted(2048, nc, 50);     /* Boxes of ammo */
  314.     addcountweighted(8, nc, 10);        /* Backpacks */
  315.     addcountweighted(3004, nc, 5);      /* Troopers */
  316.     PRINTITEM2("Bullets", nc);
  317.     for (i = 0; i < 6; i++)
  318.         wdam[i] += nc[i];               /* Accumulate damage */
  319.  
  320.     RESET(nc);
  321.     addcountweighted(2001, nc, 8);      /* Shotguns */
  322.     addcountweighted(2008, nc, 4);      /* Shells */
  323.     addcountweighted(2049, nc, 20);     /* Boxes of shells */
  324.     addcountweighted(8, nc, 4);         /* Backpacks */
  325.     addcountweighted(9, nc, 4);         /* Sergeants */
  326.     PRINTITEM2("Shells", nc);
  327.     for (i = 0; i < 6; i++)
  328.         wdam[i] += 7 * nc[i];           /* Accumulate damage */
  329.  
  330.     RESET(nc);
  331.     addcountweighted(2003, nc, 2);      /* Rocket launchers */
  332.     addcountweighted(2010, nc, 1);      /* Rockets */
  333.     addcountweighted(2046, nc, 5);      /* Boxes of rockets */
  334.     addcountweighted(8, nc, 1);         /* Backpacks */
  335.     PRINTITEM2("Rockets", nc);
  336.     for (i = 0; i < 6; i++)
  337.         wdam[i] += 20 * nc[i];          /* Accumulate damage */
  338.  
  339.     RESET(nc);
  340.     addcountweighted(2004, nc, 40);     /* Plasma guns */
  341.     addcountweighted(2006, nc, 40);     /* BFG-9000's */
  342.     addcountweighted(17, nc, 20);       /* Cell packs */
  343.     addcountweighted(2047, nc, 100);    /* Cell charges */
  344.     addcountweighted(8, nc, 20);        /* Backpacks */
  345.     PRINTITEM2("Cells", nc);
  346.     for (i = 0; i < 6; i++)
  347.         wdam[i] += 2 * nc[i];           /* Accumulate damage */
  348.  
  349.     RESET(nc);
  350.     addcountweighted(2018, nc, 100);    /* Armor */
  351.     addcountweighted(2019, nc, 200);    /* Super armor */
  352.     addcountweighted(2015, nc, 1);      /* Armor bonuses */
  353.     PRINTITEM2("Armor points", nc);
  354.  
  355.     RESET(nc);
  356.     addcountweighted(2011, nc, 10);     /* Stimpacks */
  357.     addcountweighted(2012, nc, 25);     /* Medikits */
  358.     addcountweighted(2013, nc, 100);    /* Soul spheres */
  359.     addcountweighted(2023, nc, 100);    /* Berserk strength */
  360.     addcountweighted(2014, nc, 1);      /* Health bonuses */
  361.     PRINTITEM2("Health points", nc);
  362.  
  363.     prtth(2035, "Barrels");
  364.  
  365.     /* Calculate difficulty based on damage we can do vs. damage required to
  366.      * kill all the monsters */
  367.  
  368.     printf("    Difficulty:\n");
  369.  
  370.     RESET(nc);
  371.     addcountweighted(3004, nc, 2);      /* Troopers */
  372.     addcountweighted(9, nc, 3);         /* Sergeants */
  373.     addcountweighted(3001, nc, 6);      /* Imps */
  374.     addcountweighted(3002, nc, 15);     /* Demons */
  375.     addcountweighted(58, nc, 15);       /* Spectres */
  376.     addcountweighted(3006, nc, 10);     /* Lost souls */
  377.     addcountweighted(3005, nc, 40);     /* Cacodemons */
  378.     addcountweighted(3003, nc, 100);    /* Barons */
  379.     addcountweighted(16, nc, 400);      /* Cyberdemons */
  380.     addcountweighted(7, nc, 300);       /* Spiderdemons */
  381.     PRINTITEM("Total monster hp", nc);
  382.     PRINTITEM2("Max ammo damage", wdam);
  383.  
  384.     for (i = 0; i < 6; i++)
  385.     {
  386.         if (!wdam[i])
  387.             continue;
  388.         dratio[i] = (wdam[i] ? ((float) nc[i] / (float) wdam[i]) : 0);    /* Prevent
  389.                                                                          * divide-by-zero */
  390.     }
  391.     printf("\t%-20s %0.3f %0.3f %0.3f %0.3f", "RATIO", 0.5 * dratio[0], dratio[0], dratio[1], dratio[2]);
  392.     printf(" | %0.3f %0.3f %0.3f %0.3f\n", 0.5 * dratio[3], dratio[3], dratio[4], dratio[5]);
  393.  
  394.     /*** Return success ***/
  395.  
  396.     return 1;
  397. }
  398.  
  399. /***************************************************************************/
  400.  
  401. /* Item count */
  402. #define COB(item) countth(item,battr)
  403. /* Print a character if the item is present */
  404. #define PRB0(item,char) printf("%c",(COB(item)?(char):'.'))
  405. /* Print item count, one digit */
  406. #define PRB1(item) {n=COB(item);printf((n>9?"+ ":"%d "),n);}
  407. /* Print item count, two digits */
  408. #define PRB2(item) {n=COB(item);printf((n>99?"++ ":"%2d "),n);}
  409.  
  410. int         countbriefly(void)
  411. {
  412.     /* Counts the things in a level, with one-line output format.  Returns
  413.      * zero if error. */
  414.  
  415.     long        wdam = 0;       /* Total weapon damage */
  416.     long        mhp = 0;        /* Total monster hit points */
  417.     float       dratio;         /* Damage ratio */
  418.  
  419.     long        l;
  420.     int         n, i;
  421.  
  422.     /*** Player starts ***/
  423.  
  424.     n = 0;
  425.     for (i = 1; i <= 4; i++) {          /* Find player 1-4 starts */
  426.         if (countth(i, -1))
  427.             n++;
  428.     }
  429.     printf("  %d %2ld  ", n, countth(0x11, -1));        /* Find deathmatch
  430.                                                          * starts */
  431.  
  432.     /*** Monsters ***/
  433.  
  434.     /* Bosses */
  435.     PRB2(3003);
  436.     PRB1(16);
  437.     PRB1(7);
  438.  
  439.     /* Monsters */
  440.     printf(" ");
  441.     PRB2(3004);
  442.     PRB2(9);
  443.     PRB2(3001);
  444.     PRB2(3002);
  445.     PRB2(58);
  446.     PRB2(3006);
  447.     PRB2(3005);
  448.  
  449.     /* Weapons */
  450.     putchar(' ');
  451.     PRB0(2005, '1');
  452.     putchar('2');
  453.     PRB0(2001, '3');
  454.     PRB0(2002, '4');
  455.     PRB0(2003, '5');
  456.     PRB0(2004, '6');
  457.     PRB0(2006, '7');
  458.  
  459.     /* Equipment */
  460.     printf("  ");
  461.     PRB0(8, 'B');
  462.     PRB0(2022, 'V');
  463.     PRB0(2023, 'S');
  464.     PRB0(2024, 'I');
  465.     PRB0(2025, 'R');
  466.     PRB0(2026, 'A');
  467.     PRB0(2045, 'L');
  468.  
  469.     /*** Calculate damage ratio ***/
  470.  
  471.     /** Ammo from all sources **/
  472.  
  473.     l = 20 * COB(2002) + 10 * COB(2007) + 50 * COB(2048) + 10 * COB(8) + 5 * COB(3004);
  474.     wdam += l;                          /* Bullets */
  475.  
  476.     l = 8 * COB(2001) + 4 * COB(2008) + 20 * COB(2049) + 4 * COB(8) + 4 * COB(9);
  477.     wdam += 7 * l;                      /* Shells */
  478.  
  479.     l = 2 * COB(2003) + COB(2010) + 5 * COB(2046) + COB(8);
  480.     wdam += 20 * l;                     /* Rockets */
  481.  
  482.     l = 40 * COB(2004) + 40 * COB(2006) + 20 * COB(17) + 100 * COB(2047) + 20 * COB(8);
  483.     wdam += 2 * l;                      /* Cell packs */
  484.  
  485.     /** Monster hit points **/
  486.  
  487.     mhp = 2 * COB(3004) + 3 * COB(9) + 6 * COB(3001) + 15 * COB(3002) + 15 * COB(58)
  488.           + 10 * COB(3006) + 40 * COB(3005) + 100 * COB(3003) + 400 * COB(16) + 300 * COB(7);
  489.  
  490.     dratio = (wdam ? (float) mhp / (float) wdam : 0);   /* Make sure we don't
  491.                                                          * divide by zero */
  492.     if (isbrief == 1)
  493.         dratio *= 0.5;                  /* Twice as much ammo in easiest
  494.                                          * level */
  495.  
  496.     printf("  %0.3f\n", dratio);
  497.  
  498.     /*** Return success ***/
  499.  
  500.     return 1;
  501.  
  502. }
  503.  
  504. /***************************************************************************/
  505. /***************************************************************************/
  506.  
  507. int         countlinedefs(FILE * f, long offs, long len)
  508. {
  509.     /* Counts the interesting linedefs in a map's LINEDEFS data.  Returns
  510.      * zero if error. */
  511.  
  512.     long        savepos = ftell(f);     /* Save position in WAD file */
  513.  
  514.     long        nlines = len / 14;      /* Total number of linedefs */
  515.     long        ntrig = 0;      /* Number of linedefs which do something */
  516.  
  517.     int         ibuf[7];
  518.     long        l;
  519.  
  520.     /*** Seek to the LINEDEFS data and loop through the linedefs ***/
  521.  
  522.     fseek(f, offs, SEEK_SET);
  523.  
  524.     for (l = 0; l < nlines; l++) {
  525.         fread(ibuf, sizeof(int), 7, f); /* Read a linedef */
  526.  
  527.         if (ibuf[3])
  528.             ntrig++;
  529.     }
  530.  
  531.     /*** Print information ***/
  532.  
  533.     printf("\tTriggers / linedefs    %4ld / %4ld\n", ntrig, nlines);
  534.  
  535.     /*** Seek to original file position and return success ***/
  536.  
  537.     fseek(f, savepos, SEEK_SET);
  538.     return 1;                           /* Success */
  539. }
  540.  
  541. /***************************************************************************/
  542.  
  543. int         countsectors(FILE * f, long offs, long len)
  544. {
  545.     /* Counts the interesting sectors in a map's SECTORS data.  Returns zero
  546.      * if error. */
  547.  
  548.     long        savepos = ftell(f);     /* Save position in WAD file */
  549.  
  550.     long        nsec = len / 26;/* Total number of sectors */
  551.     long        bright = 0;     /* Average brightness */
  552.     long        nnuke = 0;      /* Sectors with nukeage */
  553.     long        nsecret = 0;    /* Secret sectors */
  554.  
  555.     int         ibuf[13];
  556.     long        l;
  557.  
  558.     /*** Seek to the SECTORS data and loop through the sectors ***/
  559.  
  560.     fseek(f, offs, SEEK_SET);
  561.  
  562.     for (l = 0; l < nsec; l++) {
  563.         fread(ibuf, sizeof(int), 13, f);/* Read a sector */
  564.  
  565.         bright += ibuf[10];             /* Accumulate brightness */
  566.  
  567.         switch (ibuf[11]) {             /* Check for specials */
  568.           case 4:                       /* -20%, blinking */
  569.           case 5:                       /* -10% */
  570.           case 7:                       /* -5% */
  571.           case 11:                      /* -20%, end of level */
  572.           case 16:                      /* -20% */
  573.             nnuke++;
  574.             break;
  575.           case 9:                       /* Secret */
  576.             nsecret++;
  577.             break;
  578.         }
  579.     }
  580.  
  581.     /*** Print information ***/
  582.  
  583.     printf("\tAverage brightness            %4ld (0=dark, 255=bright)\n", bright / nsec);
  584.  
  585.     printf("\tSecrets                       %4ld\n", nsecret);
  586.     printf("\tNukeage / sectors      %4ld / %4ld\n", nnuke, nsec);
  587.  
  588.     /*** Seek to original file position and return success ***/
  589.  
  590.     fseek(f, savepos, SEEK_SET);
  591.     return 1;                           /* Success */
  592. }
  593.  
  594. /***************************************************************************/
  595. /***************************************************************************/
  596.  
  597. int         PrintAllStuff(FILE * f)
  598. {
  599.     /* Prints all information for a map.  Returns zero if error. */
  600.  
  601.  
  602.     /*** Print things ***/
  603.  
  604.     if (thlen) {
  605.         if (loadthings(f, thoff, thlen)) {      /* Load things */
  606.             if (isbrief)
  607.                 countbriefly(); /* Print brief counts */
  608.             else
  609.                 countthings();          /* Print verbose counts */
  610.             freethings();               /* Free array, restore original file
  611.                                          * position */
  612.         }
  613.     }
  614.     /*** If brief info, return now (no extended info) ***/
  615.  
  616.     if (isbrief)
  617.         return 1;
  618.  
  619.     /*** Print other info ***/
  620.  
  621.     printf("    Other info:\n");
  622.  
  623.     if (selen)
  624.         countsectors(f, seoff, selen);
  625.     if (ldlen)
  626.         countlinedefs(f, ldoff, ldlen);
  627.  
  628.     printf("\tReject resource                %s\n", (rjlen > 0 ? "YES" : " NO"));
  629.  
  630.     /*** Return success ***/
  631.  
  632.     return 1;
  633. }
  634.  
  635. /***************************************************************************/
  636.  
  637. int         handlepwad(char *fname)
  638. {
  639.     /* Handles a PWAD file.  Returns zero if error. */
  640.  
  641.     int         ispwad = 0;     /* Are we a PWAD? (or an IWAD) */
  642.  
  643.     long        ndirent;        /* Number of entries in WAD directory */
  644.     long        diroffs;        /* Offset of directory in WAD file */
  645.  
  646.     long        eoffs, elen;    /* Offset and length of a directory entry */
  647.     char        ename[9] = "entrynam";  /* Name of the entry */
  648.     int         episode = 0, mission = 0;       /* Current episode and
  649.                                                  * mission */
  650.     FILE       *f;
  651.     int         i, j;
  652.  
  653.     /*** Open the PWAD file ***/
  654.  
  655.     f = fopen(fname, "rb");
  656.     if (!f) {
  657.         fprintf(stderr, "Can't open file %s\n", fname);
  658.         return 0;
  659.     }
  660.     /*** Read the header ***/
  661.  
  662.     fread(buf, sizeof(char), 4, f);
  663.     if (!strncmp(buf, "IWAD", 4)) {
  664.         ispwad = 0;
  665.     } else if (!strncmp(buf, "PWAD", 4)) {
  666.         ispwad = 1;
  667.     } else {
  668.         printf("%s is not a DOOM WAD file\n", fname);
  669.         fclose(f);
  670.         return 0;
  671.     }
  672.  
  673.     if (!isbrief) {                     /* Start a new filename in the output */
  674.         printf("==============================================================================\n");
  675.         printf("%cWAD FILE %s:\n", (ispwad ? 'P' : 'I'), fname);
  676.     }
  677.     fread(&ndirent, sizeof(long), 1, f);/* Number of entries in WAD dir */
  678.     fread(&diroffs, sizeof(long), 1, f);/* Offset of directory in WAD */
  679.  
  680.     /*** Print the WAD directory ***/
  681.  
  682.     fseek(f, diroffs, SEEK_SET);        /* Go to the directory */
  683.  
  684.     for (i = 0; i < ndirent; i++) {
  685.  
  686.         /** Read entry **/
  687.  
  688.         fread(&eoffs, sizeof(long), 1, f);      /* Offset of entry's data */
  689.         fread(&elen, sizeof(long), 1, f);       /* Length of entry's data */
  690.         fread(&ename, sizeof(char), 8, f);      /* Name of entry */
  691.  
  692.         /** If entry is part of a level, print it **/
  693.  
  694.         for (j = 0; j < 10; j++) {
  695.             if (!strcmp(ename, contents[j]))
  696.                 break;                  /* Matched valid contents for a level */
  697.         }
  698.  
  699.         switch (j) {
  700.           case 10:                      /* Not level contents */
  701.  
  702.             if (!mission)
  703.                 break;
  704.  
  705.             /** Look at all the stuff we found **/
  706.  
  707.             PrintAllStuff(f);
  708.  
  709.             /** Reset status **/
  710.  
  711.             thlen = ldlen = selen = rjlen = 0;
  712.             episode = mission = 0;      /* No longer in a level */
  713.             break;
  714.  
  715.           case 0:                       /* THINGS */
  716.             thoff = eoffs;
  717.             thlen = elen;
  718.             break;
  719.  
  720.           case 1:                       /* LINEDEFS */
  721.             ldoff = eoffs;
  722.             ldlen = elen;
  723.             break;
  724.           case 7:                       /* SECTORS */
  725.             seoff = eoffs;
  726.             selen = elen;
  727.             break;
  728.           case 8:                       /* REJECT */
  729.             rjlen = elen;
  730.             break;
  731.         }
  732.  
  733.         /** Keep track of which mission we're looking at **/
  734.  
  735.         if (ename[0] == 'E' && isdigit(ename[1]) && ename[2] == 'M' &&
  736.             isdigit(ename[3]) && ename[4] == '\0') {
  737.             episode = ename[1] - '0';
  738.             mission = ename[3] - '0';
  739.  
  740.             if (isbrief) {              /* One-line output */
  741.                 printf("%-12.12s E%dM%d", fname, episode, mission);
  742.             } else {                    /* Verbose output */
  743.                 printf("------------------------------------------------------------------------------\n");
  744.                 printf("EPISODE %d MISSION %d             S1    S2    S3   S45 |    M1    M2    M3   M45\n", episode, mission);
  745.                 printf("------------------------------------------------------------------------------\n");
  746.             }
  747.         }
  748.     }
  749.  
  750.     /*** Look at all the stuff we found from the last map, if any ***/
  751.  
  752.     if (mission)
  753.         PrintAllStuff(f);
  754.     thlen = ldlen = selen = rjlen = 0;
  755.  
  756.     /*** Close the file and return success ***/
  757.  
  758.     fclose(f);
  759.     return 1;
  760. }
  761.  
  762. /***************************************************************************/
  763. /***************************************************************************/
  764.  
  765. int         main(int argc, char *argv[])
  766. {
  767.  
  768.     struct ffblk ff;
  769.     int         i;
  770.  
  771.     /*** Make sure we've been given a filename ***/
  772.  
  773.     printf("WADWHAT 1.1 by Randall R. Spangler (rspangle@micro.caltech.edu)\n");
  774.  
  775.     if (argc < 2) {
  776.         printf("Prints the contents of a WAD file or files.\n");
  777.         printf("Usage:\n\twadwhat [-Bn[M]] file1 [file2 ...]\n");
  778.         printf("\n\t\t-Bn\tbrief contents at skill level n\n");
  779.         printf("\t\t-BnM\tbrief contents at skill level n, multiplayer\n");
  780.         return 1;
  781.     }
  782.     /*** Match all wildcards ***/
  783.  
  784.     for (i = 1; i < argc; i++) {
  785.  
  786.         /** See if we're an option **/
  787.  
  788.         if (!strnicmp(argv[i], "-B", 2)) {      /* Print briefly */
  789.             isbrief = atoi(argv[i] + 2);/* Extract skill level */
  790.             printf("File         Map   Play  Bosses  Monsters              Weapons  Equip    RATIO\n");
  791.             printf("-------------------c-de--ba-c-s--tr-se-im-de-sp-lo-ca--cpscrpb--bvsiral-------\n");
  792.             battr = battrarry[isbrief - 1];     /* Matching attributes for
  793.                                                  * brief printout */
  794.             if (toupper(argv[i][3]) == 'M')
  795.                 battr |= 0x10;          /* Add in multi-player stuff */
  796.  
  797.             continue;
  798.         }
  799.         /** Make sure at least one matching file exists **/
  800.  
  801.         if (findfirst(argv[i], &ff, FA_ARCH)) { /* No match for wildcard */
  802.             fprintf(stderr, "Can't find file matching %s\n", argv[i]);
  803.             continue;
  804.         }
  805.         /** Handle all the matching files **/
  806.  
  807.         do {
  808.             handlepwad(ff.ff_name);
  809.         } while (!findnext(&ff));
  810.     }
  811.  
  812.     /*** Return success ***/
  813.  
  814.     return 0;
  815. }
  816.  
  817. /***************************************************************************/
  818. /***************************************************************************/
  819.