/* Doom PostScript map generator. V1.2 Copyright James Bonfield, 3/3/94 Modified for PC by Gerhard Karnik (g.karnik@att.com) 3/29/94 Enhancements (V1.2) by Gerhard Karnik (g.karnik@att.com) 5/12/94 Description ----------- This program produces PostScript maps of Doom levels, extracted from the Wad file. The program is written for the UNIX operating system, and so you need a method of transfering your doom.wad file, (or perhaps having it visible by, say, mounting your DOS partition). Thick lines represent solid walls on the map. Circles represent objects. Arrows represent the enemy. The direction of the arrow is the direction the creature is facing. Gray lines represent secret passages. USAGE: doom_ps [-o] [-m] [-dm] [wadfile] [level] -o Do not display objects -m Do not display monsters -dm Display deathmatch items wadfile Selects another wad file (default is "DOOM.WAD") level Level number (default is all levels), can use "E1M1" or "11" The postscript will then be displayed to stdout. Compiled using Borland C++ 4.0 using 'bcc -mh' */ #include #include #include #include #include #include #include #include #include #include unsigned nread; /* throw away variable for _dos_read() */ char wadfile[80], level[80]; typedef long int4; typedef short int2; struct wad_header { int4 magic; int4 dir_size; int4 dir_off; }; struct directory { int4 start; int4 length; char name[8]; }; typedef struct linedef_ { int2 from_vertex; int2 to_vertex; int2 attrib; int2 type; int2 trigger; int2 sidedef1; int2 sidedef2; } linedef; /* linedef attrib bits */ #define LI_IMPASS 0x01 #define LI_SECRET 0x20 typedef struct vertex_ { int2 x; int2 y; } vertex; typedef struct sidedef_ { int2 x; int2 y; char wall_above[8]; char wall_below[8]; char wall_part[8]; int2 sector; } sidedef; typedef struct ssector_ { int2 num; int2 seg; } ssector; typedef struct sector_ { int2 bot_pos; int2 top_pos; char bot_texture[8]; char top_texture[8]; int2 brightness; int2 special; int2 trigger; } sector; typedef struct thing_ { int2 x; int2 y; int2 angle; int2 type; int2 attrib; } thing; /* thing 'type' bits */ #define TH_SKILL1 0x01 #define TH_SKILL2 0x01 #define TH_SKILL3 0x02 #define TH_SKILL4 0x04 #define TH_MULTI 0x10 typedef int2 blockmap; void _ExceptInit(void) {}; /* reduces size of borland C++ 4.0 executable */ struct directory *open_wad(char *file, int *fd, long *size); long get_index(struct directory *d, long size, char *name, long st); linedef *read_linedefs(int fd, struct directory *d, long size, long start, long *num); vertex *read_vertexes(int fd, struct directory *d, long size, long start, long *num); blockmap *read_blockmap(int fd, struct directory *d, long size, long start, long *num); sidedef *read_sidedefs(int fd, struct directory *d, long size, long start, long *num); sector *read_sectors(int fd, struct directory *d, long size, long start, long *num); thing *read_things(int fd, struct directory *d, long size, long start, long *num); void usage(void); int doit(int fd, struct directory *dir, long size, int objs, int mons, int deathmatch); /* * Paper is 8 1/2" by 11" * We allow 1/2" border. */ #define PAPER_X (72 * 8.5) #define PAPER_Y (72 * 11) #define PAPER_BORDER (72 * 0.5) void usage() { fprintf(stderr, "Doom PostScript map generator V1.2\n"); fprintf(stderr, "Produces PostScript maps of Doom levels extracted from a WAD file.\n"); fprintf(stderr, "\n"); fprintf(stderr, "USAGE: doom_ps [-o] [-m] [-dm] [wadfile] [level]\n"); fprintf(stderr, " -o Do not display objects\n"); fprintf(stderr, " -m Do not display monsters\n"); fprintf(stderr, " -dm Display deathmatch items\n"); fprintf(stderr, " -? or -h This help screen\n"); fprintf(stderr, " wadfile Selects another wad file \(default is \"DOOM.WAD\"\)\n"); fprintf(stderr, " level Level number \(default is all levels\), can use \"E1M1\" or \"11\"\n"); fprintf(stderr, "\n"); fprintf(stderr, "Map legend:\n"); fprintf(stderr, " Thick line = Solid walls on the map\n"); fprintf(stderr, " Gray line = Secret passages\n"); fprintf(stderr, " Shaded circle = Invisibility, radiation suit, computer map, or lite goggles\n"); fprintf(stderr, " Arrow = Monster facing the direction of the arrow\n"); fprintf(stderr, " 3D box = Box of ammo\n"); fprintf(stderr, " Smiley face = Invulnerability or Soulsphere\n"); fprintf(stderr, " Cross = Stimpak, medikit, health bonus, or berserk strength\n"); fprintf(stderr, " Shirt = Green armor 100%% or blue armor 200%%\n"); exit(-1); } int main(int argc, char **argv) { struct directory *d; struct ffblk ffblk; int fd, i, ep, lv; long size; int objs = 1, mons = 1, deathmatch=0; int done; char path[80]; for(i=1; i<=argc; i++) { if(argv[i][0] == '/') argv[i][0] = '-'; if(!strcmpi(argv[i], "-DM")) deathmatch = 1; if(!strcmpi(argv[i], "-O")) objs = 0; if(!strcmpi(argv[i], "-M")) mons = 0; if(!strcmpi(argv[i], "-?")) usage(); if(!strcmpi(argv[i], "-H")) usage(); if(argv[i][0] != '-') break; /* no more params */ } switch( argc-i ) { case 0: /* no more params */ strcpy(path, "DOOM.WAD"); strcpy(level, ""); break; case 1: /* only wad name */ strcpy(path, argv[i]); strcpy(level, ""); break; case 2: /* wad name + level */ strcpy(path, argv[i]); strcpy(level, argv[i+1]); if(strlen(level) == 2) { /* convert '11' to 'E1M1' */ level[4] = 0; level[3] = level[1]; level[2] = 'M'; level[1] = level[0]; level[0] = 'E'; } break; default: usage(); } if(strlen(path)>12) fprintf(stderr, "WARNING: Can only get WADs in current directory.\n"); done = findfirst(path, &ffblk, 0); if(done) { fprintf(stderr, "Failed to open wad file \"%s\".\n", path); return -1; } while(!done) { strcpy(wadfile, ffblk.ff_name); if((d = open_wad(wadfile, &fd, &size)) != NULL) { if(!level[0]) { /* do all levels */ for(ep=1; ep<=3; ep++) for(lv=1; lv<=9; lv++) { sprintf(level, "E%dM%d", ep, lv); doit(fd, d, size, objs, mons, deathmatch); } strcpy(level, ""); } else if(doit(fd, d, size, objs, mons, deathmatch) == -1) fprintf(stderr, "Unknown level: %s\n", level); _dos_close(fd); } done = findnext(&ffblk); } return 0; } int doit(int fd, struct directory *dir, long size, int objs, int mons, int deathmatch) { linedef *linedefs; vertex *vertexes; blockmap *blocks; sidedef *sidedefs; sector *sectors; thing *things; long numline, numvert, numblock, numside, numsect, numthing; long lev_index; long xorigin, yorigin, xsize, ysize; int2 sector; double xscale, yscale; long i, j; /* find level index */ lev_index = get_index(dir, size, level, 0); if(lev_index == -1) return(-1); /* level not found */ /* load relevent arrays for this level */ linedefs = read_linedefs(fd, dir, size, lev_index, &numline); vertexes = read_vertexes(fd, dir, size, lev_index, &numvert); blocks = read_blockmap(fd, dir, size, lev_index, &numblock); sidedefs = read_sidedefs(fd, dir, size, lev_index, &numside); sectors = read_sectors(fd, dir, size, lev_index, &numsect); things = read_things(fd, dir, size, lev_index, &numthing); /* calculate scaling info */ xorigin = blocks[0]; yorigin = blocks[1]; xsize = blocks[2] * 0x80; ysize = blocks[3] * 0x80; xscale = (double) (PAPER_Y - 2 * PAPER_BORDER) / xsize; yscale = (double) (PAPER_X - 2 * PAPER_BORDER) / ysize; if(xscale > yscale) xscale = yscale; else yscale = xscale; /* output postscript header */ printf("%%!\n"); printf("newpath\n"); printf("\n"); printf("1 setlinecap\n"); printf("%f %f translate\n", PAPER_BORDER, PAPER_Y - PAPER_BORDER); printf("/Times-Roman findfont 14 scalefont setfont\n"); printf("0 setgray 20 0 moveto (%s - %s) show\n", wadfile, level); printf("-90 rotate\n"); printf("%f %f scale\n", xscale, yscale); printf("%ld %ld translate\n", -xorigin, -yorigin); printf("%f setlinewidth\n", (double) .5 / xscale); printf("\n"); printf("/Times-Roman findfont %f scalefont setfont\n", 5 / xscale); printf("/Text {\n"); printf(" gsave\n"); printf(" 0 setgray moveto show\n"); printf(" grestore\n"); printf("} def\n"); printf("\n"); printf("/l {\n"); printf(" setgray setlinewidth moveto lineto stroke\n"); printf("} def\n"); printf("\n"); printf("/a {\n"); printf(" 0.5 setgray\n"); printf(" 5 0 360 arc stroke\n"); printf("} def\n"); printf("\n"); printf("/m {\n"); printf(" gsave\n"); printf(" 0 setgray\n"); printf(" 1 setlinewidth\n"); printf(" moveto rotate\n"); printf(" 0 -13 rmoveto\n"); printf(" 0 25 rlineto\n"); printf(" -10 -10 rlineto\n"); printf(" 10 10 rmoveto\n"); printf(" 10 -10 rlineto\n"); printf(" stroke\n"); printf(" grestore\n"); printf("} def\n"); printf("\n"); printf("/ammo {\n"); printf(" gsave\n"); printf(" 0 setgray\n"); printf(" 1 setlinewidth\n"); printf(" moveto\n"); printf(" 18 0 rlineto\n"); printf(" 0 -18 rlineto\n"); printf(" -18 0 rlineto\n"); printf(" 0 18 rlineto\n"); printf(" 9 9 rlineto\n"); printf(" 18 0 rlineto\n"); printf(" -9 -9 rlineto\n"); printf(" 9 9 rmoveto\n"); printf(" 0 -18 rlineto\n"); printf(" -8 -9 rlineto\n"); printf(" stroke\n"); printf(" grestore\n"); printf("} def\n"); printf("\n"); printf("/armor {\n"); printf(" gsave\n"); printf(" 0 setgray\n"); printf(" 1 setlinewidth\n"); printf(" translate\n"); printf(" 1.5 1.5 scale\n"); printf(" 0 -5 moveto\n"); printf(" newpath\n"); printf(" 9 10 8 30 150 arc\n"); printf(" -9 10 8 30 150 arc\n"); printf(" -10 9 4 150 20 arcn\n"); printf(" 0 -12 rlineto\n"); printf(" 12 0 rlineto\n"); printf(" 0 12 rlineto\n"); printf(" 10 9 4 140 30 arcn\n"); printf(" closepath\n"); printf(" stroke\n"); printf(" grestore\n"); printf("} def\n"); printf("\n"); printf("/health {\n"); printf(" gsave\n"); printf(" 0 setgray\n"); printf(" 2 setlinewidth\n"); printf(" moveto\n"); printf(" 8 0 rlineto\n"); printf(" -16 0 rlineto\n"); printf(" 8 0 rmoveto\n"); printf(" 0 8 rlineto\n"); printf(" 0 -16 rlineto\n"); printf(" stroke\n"); printf(" grestore\n"); printf("} def\n"); printf("\n"); printf("/smiley {\n"); printf(" gsave\n"); printf(" 0 setgray\n"); printf(" 1 setlinewidth\n"); printf(" translate\n"); printf(" newpath\n"); printf(" 0 0 15 90 89 arc\n"); printf(" closepath\n"); printf(" -6 -9 rmoveto\n"); printf(" 3 0 rlineto\n"); printf(" 6 0 rmoveto\n"); printf(" 3 0 rlineto\n"); printf(" -7 -6 rmoveto\n"); printf(" 2 0 rlineto\n"); printf(" -5 -8 rmoveto\n"); printf(" 8 0 rlineto\n"); printf(" stroke\n"); printf(" grestore\n"); printf("} def\n"); printf("\n"); /* Display the walls. Secret passages are done in grey. */ for(i=0; i