home *** CD-ROM | disk | FTP | other *** search
/ WADS of WADS / WadsOfWads.1994.zip / OTHER / WADWHAT / WADWHAT.C < prev    next >
C/C++ Source or Header  |  1994-08-28  |  27KB  |  818 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.         if (!wdam[i])
  386.             continue;
  387.         dratio[i] = (wdam[i] ? (float) nc[i] / (float) wdam[i] : 0);    /* Prevent
  388.                                                                          * divide-by-zero */
  389.     }
  390.     printf("\t%-20s %0.3f %0.3f %0.3f %0.3f", "RATIO", 0.5 * dratio[0], dratio[0], dratio[1], dratio[2]);
  391.     printf(" | %0.3f %0.3f %0.3f %0.3f\n", 0.5 * dratio[3], dratio[3], dratio[4], dratio[5]);
  392.  
  393.     /*** Return success ***/
  394.  
  395.     return 1;
  396. }
  397.  
  398. /***************************************************************************/
  399.  
  400. /* Item count */
  401. #define COB(item) countth(item,battr)
  402. /* Print a character if the item is present */
  403. #define PRB0(item,char) printf("%c",(COB(item)?(char):'.'))
  404. /* Print item count, one digit */
  405. #define PRB1(item) {n=COB(item);printf((n>9?"+ ":"%d "),n);}
  406. /* Print item count, two digits */
  407. #define PRB2(item) {n=COB(item);printf((n>99?"++ ":"%2d "),n);}
  408.  
  409. int         countbriefly(void)
  410. {
  411.     /* Counts the things in a level, with one-line output format.  Returns
  412.      * zero if error. */
  413.  
  414.     long        wdam = 0;       /* Total weapon damage */
  415.     long        mhp = 0;        /* Total monster hit points */
  416.     float       dratio;         /* Damage ratio */
  417.  
  418.     long        l;
  419.     int         n, i;
  420.  
  421.     /*** Player starts ***/
  422.  
  423.     n = 0;
  424.     for (i = 1; i <= 4; i++) {          /* Find player 1-4 starts */
  425.         if (countth(i, -1))
  426.             n++;
  427.     }
  428.     printf("  %d %2ld  ", n, countth(0x11, -1));        /* Find deathmatch
  429.                                                          * starts */
  430.  
  431.     /*** Monsters ***/
  432.  
  433.     /* Bosses */
  434.     PRB2(3003);
  435.     PRB1(16);
  436.     PRB1(7);
  437.  
  438.     /* Monsters */
  439.     printf(" ");
  440.     PRB2(3004);
  441.     PRB2(9);
  442.     PRB2(3001);
  443.     PRB2(3002);
  444.     PRB2(58);
  445.     PRB2(3006);
  446.     PRB2(3005);
  447.  
  448.     /* Weapons */
  449.     putchar(' ');
  450.     PRB0(2005, '1');
  451.     putchar('2');
  452.     PRB0(2001, '3');
  453.     PRB0(2002, '4');
  454.     PRB0(2003, '5');
  455.     PRB0(2004, '6');
  456.     PRB0(2006, '7');
  457.  
  458.     /* Equipment */
  459.     printf("  ");
  460.     PRB0(8, 'B');
  461.     PRB0(2022, 'V');
  462.     PRB0(2023, 'S');
  463.     PRB0(2024, 'I');
  464.     PRB0(2025, 'R');
  465.     PRB0(2026, 'A');
  466.     PRB0(2045, 'L');
  467.  
  468.     /*** Calculate damage ratio ***/
  469.  
  470.     /** Ammo from all sources **/
  471.  
  472.     l = 20 * COB(2002) + 10 * COB(2007) + 50 * COB(2048) + 10 * COB(8) + 5 * COB(3004);
  473.     wdam += l;                          /* Bullets */
  474.  
  475.     l = 8 * COB(2001) + 4 * COB(2008) + 20 * COB(2049) + 4 * COB(8) + 4 * COB(9);
  476.     wdam += 7 * l;                      /* Shells */
  477.  
  478.     l = 2 * COB(2003) + COB(2010) + 5 * COB(2046) + COB(8);
  479.     wdam += 20 * l;                     /* Rockets */
  480.  
  481.     l = 40 * COB(2004) + 40 * COB(2006) + 20 * COB(17) + 100 * COB(2047) + 20 * COB(8);
  482.     wdam += 2 * l;                      /* Cell packs */
  483.  
  484.     /** Monster hit points **/
  485.  
  486.     mhp = 2 * COB(3004) + 3 * COB(9) + 6 * COB(3001) + 15 * COB(3002) + 15 * COB(58)
  487.           + 10 * COB(3006) + 40 * COB(3005) + 100 * COB(3003) + 400 * COB(16) + 300 * COB(7);
  488.  
  489.     dratio = (wdam ? (float) mhp / (float) wdam : 0);   /* Make sure we don't
  490.                                                          * divide by zero */
  491.     if (isbrief == 1)
  492.         dratio *= 0.5;                  /* Twice as much ammo in easiest
  493.                                          * level */
  494.  
  495.     printf("  %0.3f\n", dratio);
  496.  
  497.     /*** Return success ***/
  498.  
  499.     return 1;
  500.  
  501. }
  502.  
  503. /***************************************************************************/
  504. /***************************************************************************/
  505.  
  506. int         countlinedefs(FILE * f, long offs, long len)
  507. {
  508.     /* Counts the interesting linedefs in a map's LINEDEFS data.  Returns
  509.      * zero if error. */
  510.  
  511.     long        savepos = ftell(f);     /* Save position in WAD file */
  512.  
  513.     long        nlines = len / 14;      /* Total number of linedefs */
  514.     long        ntrig = 0;      /* Number of linedefs which do something */
  515.  
  516.     int         ibuf[7];
  517.     long        l;
  518.  
  519.     /*** Seek to the LINEDEFS data and loop through the linedefs ***/
  520.  
  521.     fseek(f, offs, SEEK_SET);
  522.  
  523.     for (l = 0; l < nlines; l++) {
  524.         fread(ibuf, sizeof(int), 7, f); /* Read a linedef */
  525.  
  526.         if (ibuf[3])
  527.             ntrig++;
  528.     }
  529.  
  530.     /*** Print information ***/
  531.  
  532.     printf("\tTriggers / linedefs    %4ld / %4ld\n", ntrig, nlines);
  533.  
  534.     /*** Seek to original file position and return success ***/
  535.  
  536.     fseek(f, savepos, SEEK_SET);
  537.     return 1;                           /* Success */
  538. }
  539.  
  540. /***************************************************************************/
  541.  
  542. int         countsectors(FILE * f, long offs, long len)
  543. {
  544.     /* Counts the interesting sectors in a map's SECTORS data.  Returns zero
  545.      * if error. */
  546.  
  547.     long        savepos = ftell(f);     /* Save position in WAD file */
  548.  
  549.     long        nsec = len / 26;/* Total number of sectors */
  550.     long        bright = 0;     /* Average brightness */
  551.     long        nnuke = 0;      /* Sectors with nukeage */
  552.     long        nsecret = 0;    /* Secret sectors */
  553.  
  554.     int         ibuf[13];
  555.     long        l;
  556.  
  557.     /*** Seek to the SECTORS data and loop through the sectors ***/
  558.  
  559.     fseek(f, offs, SEEK_SET);
  560.  
  561.     for (l = 0; l < nsec; l++) {
  562.         fread(ibuf, sizeof(int), 13, f);/* Read a sector */
  563.  
  564.         bright += ibuf[10];             /* Accumulate brightness */
  565.  
  566.         switch (ibuf[11]) {             /* Check for specials */
  567.           case 4:                       /* -20%, blinking */
  568.           case 5:                       /* -10% */
  569.           case 7:                       /* -5% */
  570.           case 11:                      /* -20%, end of level */
  571.           case 16:                      /* -20% */
  572.             nnuke++;
  573.             break;
  574.           case 9:                       /* Secret */
  575.             nsecret++;
  576.             break;
  577.         }
  578.     }
  579.  
  580.     /*** Print information ***/
  581.  
  582.     printf("\tAverage brightness            %4ld (0=dark, 255=bright)\n", bright / nsec);
  583.  
  584.     printf("\tSecrets                       %4ld\n", nsecret);
  585.     printf("\tNukeage / sectors      %4ld / %4ld\n", nnuke, nsec);
  586.  
  587.     /*** Seek to original file position and return success ***/
  588.  
  589.     fseek(f, savepos, SEEK_SET);
  590.     return 1;                           /* Success */
  591. }
  592.  
  593. /***************************************************************************/
  594. /***************************************************************************/
  595.  
  596. int         PrintAllStuff(FILE * f)
  597. {
  598.     /* Prints all information for a map.  Returns zero if error. */
  599.  
  600.  
  601.     /*** Print things ***/
  602.  
  603.     if (thlen) {
  604.         if (loadthings(f, thoff, thlen)) {      /* Load things */
  605.             if (isbrief)
  606.                 countbriefly(); /* Print brief counts */
  607.             else
  608.                 countthings();          /* Print verbose counts */
  609.             freethings();               /* Free array, restore original file
  610.                                          * position */
  611.         }
  612.     }
  613.     /*** If brief info, return now (no extended info) ***/
  614.  
  615.     if (isbrief)
  616.         return 1;
  617.  
  618.     /*** Print other info ***/
  619.  
  620.     printf("    Other info:\n");
  621.  
  622.     if (selen)
  623.         countsectors(f, seoff, selen);
  624.     if (ldlen)
  625.         countlinedefs(f, ldoff, ldlen);
  626.  
  627.     printf("\tReject resource                %s\n", (rjlen > 0 ? "YES" : " NO"));
  628.  
  629.     /*** Return success ***/
  630.  
  631.     return 1;
  632. }
  633.  
  634. /***************************************************************************/
  635.  
  636. int         handlepwad(char *fname)
  637. {
  638.     /* Handles a PWAD file.  Returns zero if error. */
  639.  
  640.     int         ispwad = 0;     /* Are we a PWAD? (or an IWAD) */
  641.  
  642.     long        ndirent;        /* Number of entries in WAD directory */
  643.     long        diroffs;        /* Offset of directory in WAD file */
  644.  
  645.     long        eoffs, elen;    /* Offset and length of a directory entry */
  646.     char        ename[9] = "entrynam";  /* Name of the entry */
  647.     int         episode = 0, mission = 0;       /* Current episode and
  648.                                                  * mission */
  649.     FILE       *f;
  650.     int         i, j;
  651.  
  652.     /*** Open the PWAD file ***/
  653.  
  654.     f = fopen(fname, "rb");
  655.     if (!f) {
  656.         fprintf(stderr, "Can't open file %s\n", fname);
  657.         return 0;
  658.     }
  659.     /*** Read the header ***/
  660.  
  661.     fread(buf, sizeof(char), 4, f);
  662.     if (!strncmp(buf, "IWAD", 4)) {
  663.         ispwad = 0;
  664.     } else if (!strncmp(buf, "PWAD", 4)) {
  665.         ispwad = 1;
  666.     } else {
  667.         printf("%s is not a DOOM WAD file\n", fname);
  668.         fclose(f);
  669.         return 0;
  670.     }
  671.  
  672.     if (!isbrief) {                     /* Start a new filename in the output */
  673.         printf("==============================================================================\n");
  674.         printf("%cWAD FILE %s:\n", (ispwad ? 'P' : 'I'), fname);
  675.     }
  676.     fread(&ndirent, sizeof(long), 1, f);/* Number of entries in WAD dir */
  677.     fread(&diroffs, sizeof(long), 1, f);/* Offset of directory in WAD */
  678.  
  679.     /*** Print the WAD directory ***/
  680.  
  681.     fseek(f, diroffs, SEEK_SET);        /* Go to the directory */
  682.  
  683.     for (i = 0; i < ndirent; i++) {
  684.  
  685.         /** Read entry **/
  686.  
  687.         fread(&eoffs, sizeof(long), 1, f);      /* Offset of entry's data */
  688.         fread(&elen, sizeof(long), 1, f);       /* Length of entry's data */
  689.         fread(&ename, sizeof(char), 8, f);      /* Name of entry */
  690.  
  691.         /** If entry is part of a level, print it **/
  692.  
  693.         for (j = 0; j < 10; j++) {
  694.             if (!strcmp(ename, contents[j]))
  695.                 break;                  /* Matched valid contents for a level */
  696.         }
  697.  
  698.         switch (j) {
  699.           case 10:                      /* Not level contents */
  700.  
  701.             if (!mission)
  702.                 break;
  703.  
  704.             /** Look at all the stuff we found **/
  705.  
  706.             PrintAllStuff(f);
  707.  
  708.             /** Reset status **/
  709.  
  710.             thlen = ldlen = selen = rjlen = 0;
  711.             episode = mission = 0;      /* No longer in a level */
  712.             break;
  713.  
  714.           case 0:                       /* THINGS */
  715.             thoff = eoffs;
  716.             thlen = elen;
  717.             break;
  718.  
  719.           case 1:                       /* LINEDEFS */
  720.             ldoff = eoffs;
  721.             ldlen = elen;
  722.             break;
  723.           case 7:                       /* SECTORS */
  724.             seoff = eoffs;
  725.             selen = elen;
  726.             break;
  727.           case 8:                       /* REJECT */
  728.             rjlen = elen;
  729.             break;
  730.         }
  731.  
  732.         /** Keep track of which mission we're looking at **/
  733.  
  734.         if (ename[0] == 'E' && isdigit(ename[1]) && ename[2] == 'M' &&
  735.             isdigit(ename[3]) && ename[4] == '\0') {
  736.             episode = ename[1] - '0';
  737.             mission = ename[3] - '0';
  738.  
  739.             if (isbrief) {              /* One-line output */
  740.                 printf("%-12.12s E%dM%d", fname, episode, mission);
  741.             } else {                    /* Verbose output */
  742.                 printf("------------------------------------------------------------------------------\n");
  743.                 printf("EPISODE %d MISSION %d             S1    S2    S3   S45 |    M1    M2    M3   M45\n", episode, mission);
  744.                 printf("------------------------------------------------------------------------------\n");
  745.             }
  746.         }
  747.     }
  748.  
  749.     /*** Look at all the stuff we found from the last map, if any ***/
  750.  
  751.     if (mission)
  752.         PrintAllStuff(f);
  753.     thlen = ldlen = selen = rjlen = 0;
  754.  
  755.     /*** Close the file and return success ***/
  756.  
  757.     fclose(f);
  758.     return 1;
  759. }
  760.  
  761. /***************************************************************************/
  762. /***************************************************************************/
  763.  
  764. int         main(int argc, char *argv[])
  765. {
  766.  
  767.     struct ffblk ff;
  768.     int         i;
  769.  
  770.     /*** Make sure we've been given a filename ***/
  771.  
  772.     printf("WADWHAT 1.1 by Randall R. Spangler (rspangle@micro.caltech.edu)\n");
  773.  
  774.     if (argc < 2) {
  775.         printf("Prints the contents of a WAD file or files.\n");
  776.         printf("Usage:\n\twadwhat [-Bn[M]] file1 [file2 ...]\n");
  777.         printf("\n\t\t-Bn\tbrief contents at skill level n\n");
  778.         printf("\t\t-BnM\tbrief contents at skill level n, multiplayer\n");
  779.         return 1;
  780.     }
  781.     /*** Match all wildcards ***/
  782.  
  783.     for (i = 1; i < argc; i++) {
  784.  
  785.         /** See if we're an option **/
  786.  
  787.         if (!strnicmp(argv[i], "-B", 2)) {      /* Print briefly */
  788.             isbrief = atoi(argv[i] + 2);/* Extract skill level */
  789.             printf("File         Map   Play  Bosses  Monsters              Weapons  Equip    RATIO\n");
  790.             printf("-------------------c-de--ba-c-s--tr-se-im-de-sp-lo-ca--cpscrpb--bvsiral-------\n");
  791.             battr = battrarry[isbrief - 1];     /* Matching attributes for
  792.                                                  * brief printout */
  793.             if (toupper(argv[i][3]) == 'M')
  794.                 battr |= 0x10;          /* Add in multi-player stuff */
  795.  
  796.             continue;
  797.         }
  798.         /** Make sure at least one matching file exists **/
  799.  
  800.         if (findfirst(argv[i], &ff, FA_ARCH)) { /* No match for wildcard */
  801.             fprintf(stderr, "Can't find file matching %s\n", argv[i]);
  802.             continue;
  803.         }
  804.         /** Handle all the matching files **/
  805.  
  806.         do {
  807.             handlepwad(ff.ff_name);
  808.         } while (!findnext(&ff));
  809.     }
  810.  
  811.     /*** Return success ***/
  812.  
  813.     return 0;
  814. }
  815.  
  816. /***************************************************************************/
  817. /***************************************************************************/
  818.