home *** CD-ROM | disk | FTP | other *** search
/ Doom Magazine 1 / Doom_magazine_01.bin / editeurs / vnb / vnb.c < prev    next >
C/C++ Source or Header  |  1994-05-25  |  21KB  |  514 lines

  1. /******************************************************************************
  2.     PROGRAM:    VNB.C
  3.     WRITTEN BY:    Robert Fenske, Jr. (rfenske@swri.edu)
  4.                 Southwest Research Institute
  5.                 Electromagnetics Division
  6.                 6220 Culebra
  7.                 San Antonio, Texas 78238-5166
  8.     CREATED:    May  1994
  9.     DESCRIPTION:    This program is the VERDA Node Builder.  It extracts
  10.             the data from a DOOM-related PWAD, IWAD, or VERDA
  11.             patch file and builds the BSP-related structures segs,
  12.             subsectors, and nodes.  It can build these structures
  13.             for all the levels in the input file, or for a specific
  14.             level found in the input file.  The command line
  15.             arguments are as follows:
  16.                 [-e#m#] <input file> [output file]
  17.             where -e#m# specifies a particular level within the
  18.             input level, input file is the input filename, and
  19.             output file is the optional output filename.  If no
  20.             output file is specified, the input file is rewritten
  21.             with the new data.
  22.  
  23.             This program has been compiled and run under SunOS
  24.             using cc and under MS-DOS using DJGPP.
  25.  
  26.             There is a number of byte swapping calls used in the
  27.             SunOS case; these calls are ugly, but necessary since
  28.             the WAD files store data in little-endian order.
  29.  
  30.             DOOM is a trademark of id Software, Inc.
  31. ******************************************************************************/
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <math.h>
  35. #include "dmglobal.i"
  36.  
  37. #define SOFTVER        1.050            /* software version */
  38. #define SOFTDATE    "May 1994"        /* software version date */
  39.  
  40. #define RESOURCES_NEEDED ((1<<LINES)|(1<<VERTS))
  41.  
  42. #define update_resource(s,d,n) \
  43.             (blockfree(WInfo.data[WInfo.lvlndx+(s)]),\
  44.              WInfo.data[WInfo.lvlndx+(s)] = (char *)(d),\
  45.              WInfo.dir[WInfo.lvlndx+(s)].nbytes = \
  46.                                          (long)(n)*datasize[s],\
  47.              WInfo.changed[WInfo.lvlndx+(s)] = TRUE)
  48.  
  49. global WAD_INFO WInfo;                /* WAD information */
  50.  
  51. local long datasize[] = { 1, sizeof(DOOM_VERT), sizeof(DOOM_LINE),
  52.               sizeof(DOOM_SIDE), sizeof(DOOM_VERT),
  53.               sizeof(DOOM_SEGS), sizeof(DOOM_SSECTOR),
  54.               sizeof(DOOM_NODE), sizeof(DOOM_SECTOR),
  55.               sizeof(DOOM_REJECT), sizeof(DOOM_BLOCKMAP)
  56. };
  57.  
  58.  
  59. /******************************************************************************
  60.     ROUTINE:    main(ac,av)
  61.     WRITTEN BY:    Robert Fenske, Jr.
  62.     CREATED:    May  1994
  63.     DESCRIPTION:    This routine processes the command line arguments
  64.             and executes the appropriate build function.
  65. ******************************************************************************/
  66. main(ac,av)
  67. int ac;
  68. char *av[];
  69. {
  70.   char *ifile = NULL, *ofile = NULL;        /* input/output filenames */
  71.   boolean help = FALSE;                /* whether to display help */
  72.   boolean good = FALSE;                /* whether read/write worked */
  73.   boolean rewrite;                /* whether input rewritten */
  74.   boolean wad = FALSE,                /* (I/P)WAD file flag */
  75.           patch = FALSE;            /* VERDA patch file flag */
  76.   int epdo = 0, mpdo = 0;            /* specific ep/map to do */
  77.   register FILE *ifp, *ofp;            /* input/output file ptrs */
  78.   register int i;
  79.  
  80.   setbuf(stdout,(char *)NULL);            /* make stdout unbuffered */
  81.   printf("\n\t\t\t\tVERDA Node Builder\n");
  82.   printf("\tVersion %5.3lf of %s by Robert Fenske, Jr (rfenske@swri.edu)\n",
  83.          SOFTVER,SOFTDATE);
  84.   for (i = 1; i < ac; i++) {            /* scan all arguments */
  85.     if (av[i][0] == '-') {
  86.       if (2 != sscanf(av[i],"-e%1dm%1d",&epdo,&mpdo)) help = TRUE;
  87.     }else if (ifile == NULL)
  88.       ifile = ofile = av[i];
  89.     else
  90.       ofile = av[i];
  91.   }
  92.   if (ifile == NULL || help) {            /* show now to do corectly */
  93.     printf("\n%s [-e#m#] <input file> [output file]\n\n",av[0]);
  94.     printf("%*s -e#m#          specify level to process;\n",
  95.            strlen(av[0]),"");
  96.     printf("%*s                otherwise does all levels\n",
  97.            strlen(av[0]),"");
  98.     printf("%*s <input file>   PWAD, IWAD, or VERDA patch file\n",
  99.             strlen(av[0]),"");
  100.     printf("%*s <output file>  output file; if none specified,\n",
  101.             strlen(av[0]),"");
  102.     printf("%*s                input file is rewritten\n",
  103.            strlen(av[0]),"");
  104.     return 1;
  105.   }
  106.   ifp = fopen(ifile,"rb");            /* open input file */
  107.   if (ifp == NULL) {
  108.     fprintf(stderr,"\nunable to open %s for reading\n",ifile);
  109.     return 1;
  110.   }
  111.   fread((char *)&WInfo.head,sizeof WInfo.head,1,ifp);
  112.   if (strncmp(WInfo.head.ident,"PWAD",4) == 0 ||
  113.       strncmp(WInfo.head.ident,"IWAD",4) == 0) wad = TRUE;
  114.   rewind(ifp);
  115.   if (2 == fscanf(ifp," %d %d %*d %*lf",&WInfo.ep,&WInfo.mp)) patch = TRUE;
  116.   if (!wad && !patch) {                /* not a valid file */
  117.     fprintf(stderr,"\n%s is not a PWAD, IWAD, nor VERDA patch file\n",ifile);
  118.     return 1;
  119.   }
  120.   rewrite = !patch && ifile == ofile;        /* whether input rewritten */
  121.   WInfo.lvlndx = -ALL;
  122.   do {                        /* process file until done */
  123.     printf("\nReading %s file %s...",patch?"patch":"WAD",ifile);
  124.     if (patch)     good = patch_read(ifp,epdo,mpdo,RESOURCES_NEEDED);
  125.     else if (wad)  good = wad_read(ifp,epdo,mpdo,RESOURCES_NEEDED);
  126.     if (good) {                    /* process new level data */
  127.       DOOM_LINE *lines = Lines;
  128.       DOOM_VERT *verts = Verts;
  129.       DOOM_SEGS *segs = Segs;
  130.       DOOM_SSECTOR *ssecs = Ssecs;
  131.       DOOM_NODE *nodes = Nodes;
  132.       DOOM_BLOCKMAP *blockmaps = Blockmaps;
  133.       printf("done\n");
  134.       printf("Building BSP Tree for level E%1dM%1d...",WInfo.ep,WInfo.mp);
  135.       nodes_make(&nodes,&NNodes,&ssecs,&NSsecs,&segs,&NSegs,&verts,&NVerts,
  136.                  &lines,&NLines);
  137.       update_resource(VERTS,verts,NVerts);
  138.       update_resource(SEGS,segs,NSegs);
  139.       update_resource(SSECTS,ssecs,NSsecs);
  140.       update_resource(NODES,nodes,NNodes);
  141.       printf("%d nodes, %d segs          \n",NNodes,NSegs);
  142.       printf("Building BLOCKMAP for level E%1dM%1d...",WInfo.ep,WInfo.mp);
  143.       NBlockmaps = blockmap_make(&blockmaps,Lines,NLines,Verts);
  144.       for (i = 0; i < NBlockmaps; i++)
  145.         blockmaps[i] = bswapw(blockmaps[i]);
  146.       update_resource(BLKMAPS,blockmaps,NBlockmaps);
  147.       printf("done\n");
  148.     }else if (WInfo.lvlndx >= 0)        /* no more in file */
  149.       printf("no more levels\n");
  150.     else                    /* oops: bogus data */
  151.       printf("failed\n");
  152.     if (good) {                    /* if processed, write it */
  153.       ofp = fopen(ofile,rewrite?"r+b":"wb");
  154.       if (ofp == NULL) {
  155.         fprintf(stderr,"unable to open %s for writing\n",ofile);
  156.         return 1;
  157.       }
  158.       printf("Writing %s file %s...",patch?"patch":"WAD",ofile);
  159.       if (patch)     good = patch_write(ifp,ofp,rewrite);
  160.       else if (wad)  good = wad_write(ifp,ofp,rewrite);
  161.       fclose(ofp);
  162.       if (good) printf("done\n");
  163.       else      printf("failed\n");
  164.     }
  165.   } while (good);
  166.   fclose(ifp);
  167.   return 0;                    /* everything is okay */
  168. }
  169.  
  170.  
  171. /******************************************************************************
  172.     ROUTINE:    patch_read(patch,epdo,mpdo,resources_needed)
  173.     WRITTEN BY:    Robert Fenske, Jr.
  174.     CREATED:    May  1994
  175.     DESCRIPTION:    This routine reads a VERDA patch file.  It reads the
  176.             file twice; the first time is to obtain the sizes of
  177.             each of the resources.  The input resources_needed is
  178.             ignored--everything in the patch file is read.  Also,
  179.             only one level's data is stored in a patch file.
  180. ******************************************************************************/
  181. patch_read(patch,epdo,mpdo,resources_needed)
  182. register FILE *patch;
  183. int epdo, mpdo, resources_needed;
  184. {
  185.   char str[256];
  186.   int type;
  187.   int i = 0;
  188.   register int t = 0, l = 0, s = 0, v = 0, c = 0;
  189.  
  190.   WInfo.lvlndx += ALL;
  191.   if (WInfo.lvlndx != 0)            /* can't do more than one */
  192.     return FALSE;                /* level with patch file  */
  193.   WInfo.dir = blockmem(DIR_ENTRY,WInfo.head.count = ALL);
  194.   WInfo.data = blockmem(char *,WInfo.head.count);
  195.   WInfo.changed = blockmem(boolean,WInfo.head.count);
  196.   WInfo.count = blockmem(int,WInfo.head.count);
  197.   sprintf(WInfo.dir[WInfo.lvlndx+MAINS].name,"E%1dM%1d",WInfo.ep,WInfo.mp);
  198.   rewind(patch);
  199.   while (fgets(str,sizeof str,patch) != NULL) {
  200.     if (i == 0) {
  201.       i = sscanf(str," %d %d %d %lf",&WInfo.ep,&WInfo.mp,&type,&WInfo.ver);
  202.       if (i && epdo && mpdo && (WInfo.mp+1 != epdo || WInfo.ep+1 != mpdo))
  203.         return FALSE;                /* doesn't match desired */
  204.       continue;                    /* level                 */
  205.     }
  206.     switch (type) {
  207.       bcase THINGS: i = str[0] != '%'; if (i) t++;
  208.       bcase LINES:  i = str[0] != '%'; if (i) l++;
  209.       bcase SIDES:  i = str[0] != '%'; if (i) s++;
  210.       bcase VERTS:  i = str[0] != '%'; if (i) v++;
  211.       bcase SEGS:   i = str[0] != '%';
  212.       bcase SSECTS: i = str[0] != '%';
  213.       bcase NODES:  i = str[0] != '%';
  214.       bcase SECTS:  i = str[0] != '%'; if (i) c++;
  215.     }
  216.   }
  217.   WInfo.data[THINGS] = (char *)blockmem(DOOM_THING, WInfo.count[THINGS] = t);
  218.   WInfo.data[LINES]  = (char *)blockmem(DOOM_LINE,  WInfo.count[LINES]  = l);
  219.   WInfo.data[SIDES]  = (char *)blockmem(DOOM_SIDE,  WInfo.count[SIDES]  = s);
  220.   WInfo.data[VERTS]  = (char *)blockmem(DOOM_VERT,  WInfo.count[VERTS]  = v);
  221.   WInfo.data[SECTS]  = (char *)blockmem(DOOM_SECTOR,WInfo.count[SECTS]  = c);
  222.   i = t = l = s = v = c = 0;
  223.   rewind(patch);
  224.   while (fgets(str,sizeof str,patch) != NULL) {
  225.     if (i == 0) {
  226.       i = sscanf(str," %d %d %d %lf",&WInfo.ep,&WInfo.mp,&type,&WInfo.ver);
  227.       continue;
  228.     }
  229.     switch (type) {
  230.       bcase THINGS:                /* THINGS */
  231.     i = sscanf(str,"%*d %4hx %4hx %3hd %4hx %4hx",
  232.            &Things[t].x,&Things[t].y,&Things[t].angle,
  233.            &Things[t].flag,&Things[t].item);
  234.     if (i==5) t++;
  235.       bcase LINES:                /* LINES */
  236.     i = sscanf(str,"%*d %4hx %4hx %4hx %4hx %4hx %4hx %4hx",
  237.            &Lines[l].fndx,&Lines[l].tndx,&Lines[l].flag,
  238.            &Lines[l].action_flag,&Lines[l].sect_tag,
  239.            &Lines[l].rsidndx,&Lines[l].lsidndx);
  240.     if (i==7) l++;
  241.       bcase SIDES:                /* SIDES */
  242.     i = sscanf(str,"%*d %4hx %4hx %8c %8c %8c %4hx",
  243.            &Sides[s].image_xoff,&Sides[s].image_yoff,
  244.            Sides[s].lowwall,Sides[s].highwall,Sides[s].fullwall,
  245.            &Sides[s].sectndx);
  246.     if (i==6) s++; else i = 0;
  247.       bcase VERTS:                /* VERTEXES */
  248.     i = sscanf(str,"%*d %4hx %4hx",&Verts[v].x,&Verts[v].y);
  249.     if (i==2) v++;
  250.       bcase SEGS:    i = str[0] != '%';        /* SEGS */
  251.       bcase SSECTS:  i = str[0] != '%';        /* SSECTORS */
  252.       bcase NODES:   i = str[0] != '%';        /* NODES */
  253.       bcase SECTS:                /* SECTORS */
  254.     i = sscanf(str,"%*d %4hx %4hx %8c %8c %4hx %4hx %4hx",
  255.            &Sects[c].floor_ht,&Sects[c].ceil_ht,Sects[c].floor_desc,
  256.            Sects[c].ceil_desc,&Sects[c].light_lvl,&Sects[c].property,
  257.            &Sects[c].line_tag);
  258.     if (i==7) c++; else i = 0;
  259.     }
  260.   }
  261.   NThings = t;
  262.   NLines = l;
  263.   NSides = s;
  264.   NVerts = v;
  265.   NSects = c;
  266.   WInfo.ep++; WInfo.mp++;
  267.   return TRUE;
  268. }
  269.  
  270.  
  271. /******************************************************************************
  272.     ROUTINE:    patch_write(rpatch,wpatch,rewrite)
  273.     WRITTEN BY:    Robert Fenske, Jr.
  274.     CREATED:    May  1994
  275.     DESCRIPTION:    This routine writes a VERDA patch file.  Only one
  276.             level's data is stored in a patch file.
  277. ******************************************************************************/
  278. patch_write(rpatch,wpatch,rewrite)
  279. register FILE *rpatch, *wpatch;
  280. boolean rewrite;
  281. {
  282.   register int i;
  283.  
  284.   if (WInfo.lvlndx != 0)            /* can't do more than one */
  285.     return FALSE;                /* level with patch file  */
  286.   fprintf(wpatch,"%d %d %d %4.2lf\n",--WInfo.ep,--WInfo.mp,THINGS,WInfo.ver);
  287.   for (i = 0; i < NThings; i++)
  288.     fprintf(wpatch,"%03d %04x %04x %03d %04x %02x\n",i,
  289.        (ushort)Things[i].x,(ushort)Things[i].y,Things[i].angle,
  290.        Things[i].flag,Things[i].item);
  291.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,LINES,WInfo.ver);
  292.   for (i = 0; i < NLines; i++)
  293.     fprintf(wpatch,"%03d %04x %04x %04x %04x %04x %04x %04x\n",i,
  294.        Lines[i].fndx,Lines[i].tndx,
  295.        (ushort)Lines[i].flag,(ushort)Lines[i].action_flag,
  296.        (ushort)Lines[i].sect_tag,
  297.        (ushort)Lines[i].rsidndx,(ushort)Lines[i].lsidndx);
  298.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,SIDES,WInfo.ver);
  299.   for (i = 0; i < NSides; i++)
  300.     fprintf(wpatch,"%03d %04x %04x %-8.8s %-8.8s %-8.8s %03x\n",i,
  301.        (ushort)Sides[i].image_xoff,(ushort)Sides[i].image_yoff,
  302.        Sides[i].lowwall,Sides[i].highwall,Sides[i].fullwall,
  303.        Sides[i].sectndx);
  304.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,VERTS,WInfo.ver);
  305.   for (i = 0; i < NVerts; i++)
  306.     fprintf(wpatch,"%03d %04x %04x\n",i,
  307.        (ushort)Verts[i].x,(ushort)Verts[i].y);
  308.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,SEGS,WInfo.ver);
  309.   for (i = 0; i < NSegs; i++)
  310.     fprintf(wpatch,"%03d %04x %04x %04x %04x %04x %04x\n",i,
  311.        Segs[i].fndx,Segs[i].tndx,(ushort)Segs[i].angle,
  312.        Segs[i].lndx,Segs[i].sndx,Segs[i].loffset);
  313.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,SSECTS,WInfo.ver);
  314.   for (i = 0; i < NSsecs; i++)
  315.     fprintf(wpatch,"%03d %04x %04x\n",i,
  316.        Ssecs[i].count,Ssecs[i].sndx);
  317.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,NODES,WInfo.ver);
  318.   for (i = 0; i < NNodes; i++)
  319.     fprintf(wpatch,"%03d \
  320. %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",i,
  321.        (ushort)Nodes[i].x,(ushort)Nodes[i].y,
  322.        (ushort)Nodes[i].xdel,(ushort)Nodes[i].ydel,
  323.        (ushort)Nodes[i].rymax,(ushort)Nodes[i].rymin,
  324.        (ushort)Nodes[i].rxmin,(ushort)Nodes[i].rxmax,
  325.        (ushort)Nodes[i].lymax,(ushort)Nodes[i].lymin,
  326.        (ushort)Nodes[i].lxmin,(ushort)Nodes[i].lxmax,
  327.        (ushort)Nodes[i].nndx[0],(ushort)Nodes[i].nndx[1]);
  328.   fprintf(wpatch,"%%\n%d %d %d %4.2lf\n",WInfo.ep,WInfo.mp,SECTS,WInfo.ver);
  329.   for (i = 0; i < NSects; i++)
  330.     fprintf(wpatch,"%03d %04x %04x %-8.8s %-8.8s %04x %04x %04x\n",i,
  331.        (ushort)Sects[i].floor_ht,(ushort)Sects[i].ceil_ht,
  332.        Sects[i].floor_desc,Sects[i].ceil_desc,
  333.        Sects[i].light_lvl,Sects[i].property,(ushort)Sects[i].line_tag);
  334.   return TRUE;
  335. }
  336.  
  337.  
  338. /******************************************************************************
  339.     ROUTINE:    wad_bswap(resource,type)
  340.     WRITTEN BY:    Robert Fenske, Jr.
  341.     CREATED:    May  1994
  342.     DESCRIPTION:    This routine swaps the bytes in the short integer
  343.             fields of the various resources.  This is necessary
  344.             since the data files store integers in Intel little-
  345.             endian order, while all real systems use big-endian
  346.             order.
  347. ******************************************************************************/
  348. void wad_bswap(resource,type)
  349. int resource, type;
  350. {
  351. #if defined(BSWAP)                /* non-Intel only */
  352.   int cnt = WInfo.dir[resource].nbytes/datasize[type];/* # items */
  353.   short *data = (short *)WInfo.data[resource];    /* where data is */
  354.   register int d, w;
  355.  
  356.   if (data != NULL)
  357.     switch (type) {
  358.       bcase THINGS:
  359.        case LINES:
  360.        case VERTS:
  361.        case SEGS:
  362.        case SSECTS:
  363.        case NODES:
  364.         for (d = 0; d < cnt; d++)
  365.           for (w = 0; w < datasize[type]/2; w++)
  366.             data[d*datasize[type]/2+w] = bswapw(data[d*datasize[type]/2+w]);
  367.       bcase SIDES:                /* only swap integer fields */
  368.         for (d = 0; d < cnt; d++) {
  369.           Sides[d].image_xoff = bswapw(Sides[d].image_xoff);
  370.           Sides[d].image_yoff = bswapw(Sides[d].image_yoff);
  371.           Sides[d].sectndx = bswapw(Sides[d].sectndx);
  372.         }
  373.       bcase SECTS:                /* only swap integer fields */
  374.         for (d = 0; d < cnt; d++) {
  375.           Sects[d].floor_ht = bswapw(Sects[d].floor_ht);
  376.           Sects[d].ceil_ht = bswapw(Sects[d].ceil_ht);
  377.           Sects[d].light_lvl = bswapw(Sects[d].light_lvl);
  378.           Sects[d].property = bswapw(Sects[d].property);
  379.           Sects[d].line_tag = bswapw(Sects[d].line_tag);
  380.         }
  381.     }
  382. #endif
  383. }
  384.  
  385.  
  386. /******************************************************************************
  387.     ROUTINE:    wad_read(wad,epdo,mpdo,resources_needed)
  388.     WRITTEN BY:    Robert Fenske, Jr.
  389.     CREATED:    May  1994
  390.     DESCRIPTION:    This routine reads a WAD file.  It reads the next
  391.             unprocessed level if epdo and mpdo are zero, or
  392.             reads the level referenced by epdo and mpdo.
  393.             resources_needed governs which resources from the
  394.             level are actually read.  The WAD file header is read,
  395.             then the resource directory, then the requested
  396.             resources.  The resource directory is held in two
  397.             locations--one for modification and one to preserve
  398.             the original directory.
  399. ******************************************************************************/
  400. wad_read(wad,epdo,mpdo,resources_needed)
  401. register FILE *wad;
  402. int epdo, mpdo, resources_needed;
  403. {
  404.   register int e, i;
  405.  
  406.   rewind(wad);
  407.   fread((char *)&WInfo.head,sizeof WInfo.head,1,wad);
  408.   WInfo.head.count = bswapl(WInfo.head.count);
  409.   WInfo.head.offset = bswapl(WInfo.head.offset);
  410.   WInfo.origdir = blockmem(DIR_ENTRY,WInfo.head.count);
  411.   WInfo.dir = blockmem(DIR_ENTRY,WInfo.head.count);
  412.   WInfo.data = blockmem(char *,WInfo.head.count);
  413.   WInfo.changed = blockmem(boolean,WInfo.head.count);
  414.   WInfo.count = blockmem(int,WInfo.head.count);
  415.   fseek(wad,WInfo.head.offset,0L);        /* read directory */
  416.   fread((char *)WInfo.origdir,(unsigned)WInfo.head.count,
  417.         sizeof(*WInfo.origdir),wad);
  418.   for (e = 0; e < WInfo.head.count; e++) {
  419.     WInfo.dir[e] = WInfo.origdir[e];
  420.     WInfo.dir[e].offset =
  421.     WInfo.origdir[e].offset = bswapl(WInfo.origdir[e].offset);
  422.     WInfo.dir[e].nbytes =
  423.     WInfo.origdir[e].nbytes = bswapl(WInfo.origdir[e].nbytes);
  424.     
  425.   }
  426.   for (e = 0; e < WInfo.lvlndx; e++) blockfree(WInfo.data[e]);
  427.   for (e = WInfo.lvlndx+ALL; e < WInfo.head.count; e++)
  428.     if (2 == sscanf(WInfo.dir[e].name,"E%1dM%1d",&WInfo.ep,&WInfo.mp) &&
  429.         (epdo == 0 && mpdo == 0 || epdo == WInfo.ep && mpdo == WInfo.mp))
  430.       break;                    /* found level */
  431.   if (e >= WInfo.head.count)            /* no more levels to process */
  432.     return FALSE;
  433.   WInfo.lvlndx = e;                              /* this map's info is here */
  434.   for (i = 0; i < ALL; i++) {
  435.     if (resources_needed & (1<<i)) {        /* get requested resources */
  436.       WInfo.data[e+i] = blockmem(char,WInfo.dir[e+i].nbytes);
  437.       fseek(wad,WInfo.dir[e+i].offset,0L);
  438.       fread(WInfo.data[e+i],(unsigned)WInfo.dir[e+i].nbytes,1,wad);
  439.       wad_bswap(e+i,i);
  440.     }else
  441.       WInfo.data[e+i] = NULL;            /* no data for resource */
  442.     WInfo.count[e+i] = WInfo.dir[e+i].nbytes/datasize[i];
  443.   }
  444.   return TRUE;
  445. }
  446.  
  447.  
  448. /******************************************************************************
  449.     ROUTINE:    wad_write(rwad,wwad,rewrite)
  450.     WRITTEN BY:    Robert Fenske, Jr.
  451.     CREATED:    May  1994
  452.     DESCRIPTION:    This routine writes a WAD file.  If rewrite is TRUE,
  453.             then the input file is being rewritten with the new
  454.             data; otherwise, a new file is written.  The resources
  455.             are written out in reverse order; this easily handles
  456.             the case where the input file is being rewritten and
  457.             some of the resources have grown in size.  Also in
  458.             the rewrite case, if a resource is smaller than before,
  459.             it is marked with the new smaller size but the
  460.             following resources are not "shifted down".  Thus there
  461.             will be some parts of the file that will be unused.
  462. ******************************************************************************/
  463. wad_write(rwad,wwad,rewrite)
  464. register FILE *rwad, *wwad;
  465. boolean rewrite;
  466. {
  467.   long dir_offset;                /* new directory offset */
  468.   char *buf;                    /* temporary data buffer */
  469.   register int e;
  470.  
  471.   for (e = 0; e < ALL; e++) wad_bswap(WInfo.lvlndx+e,e);
  472.   for (e = 1; e < WInfo.head.count; e++) {    /* compute new directory */
  473.     if (!rewrite || WInfo.origdir[e-1].offset == 0)
  474.       WInfo.dir[e].offset = WInfo.dir[e-1].offset + WInfo.dir[e-1].nbytes;
  475.     else
  476.       WInfo.dir[e].offset = WInfo.dir[e-1].offset +
  477.                             max(WInfo.dir[e-1].nbytes,
  478.                                 WInfo.origdir[e].offset-
  479.                                 WInfo.origdir[e-1].offset);
  480.   }
  481.   for (e = WInfo.head.count-1; e >= WInfo.lvlndx; e--) {/* write resources */
  482.     if (WInfo.changed[e]) {
  483.       fseek(wwad,WInfo.dir[e].offset,0L);
  484.       fwrite(WInfo.data[e],(unsigned)WInfo.dir[e].nbytes,1,wwad);
  485.       WInfo.changed[e] = FALSE;
  486.     }else if (!rewrite || WInfo.origdir[e].offset != WInfo.dir[e].offset) {
  487.       buf = blockmem(char,WInfo.origdir[e].nbytes);
  488.       fseek(rwad,WInfo.origdir[e].offset,0L);
  489.       fread(buf,(unsigned)WInfo.origdir[e].nbytes,sizeof(*buf),rwad);
  490.       fseek(wwad,WInfo.dir[e].offset,0L);
  491.       fwrite(buf,(unsigned)WInfo.origdir[e].nbytes,sizeof(*buf),wwad);
  492.       blockfree(buf);
  493.     }
  494.   }
  495.   blockfree(WInfo.origdir);            /* done with original dir */
  496.   dir_offset = WInfo.dir[WInfo.head.count-1].offset +
  497.                WInfo.dir[WInfo.head.count-1].nbytes;
  498.   for (e = 0; e < WInfo.head.count; e++) {
  499.     WInfo.dir[e].offset = bswapl(WInfo.dir[e].offset);
  500.     WInfo.dir[e].nbytes = bswapl(WInfo.dir[e].nbytes);
  501.   }
  502.   fseek(wwad,dir_offset,0L);            /* write new directory */
  503.   fwrite(WInfo.dir,(unsigned)WInfo.head.count,sizeof(*WInfo.dir),wwad);
  504.   WInfo.head.offset = bswapl(dir_offset);
  505.   WInfo.head.count = bswapl(WInfo.head.count);
  506.   fseek(wwad,0L,0L);
  507.   fwrite(&WInfo.head,sizeof(WInfo.head),1,wwad);/* write new header */
  508.   blockfree(WInfo.dir);                /* done with these */
  509.   blockfree(WInfo.data);
  510.   blockfree(WInfo.changed);
  511.   blockfree(WInfo.count);
  512.   return TRUE;
  513. }
  514.