home *** CD-ROM | disk | FTP | other *** search
/ Toolkit for DOOM / DOOMTOOL.ISO / editors / dme301.zip / SOURCE.ZIP / MAIN.C < prev    next >
C/C++ Source or Header  |  1994-08-03  |  72KB  |  3,426 lines

  1. /*
  2.     This is a DMapEdit source code module.  Though it is copyrighted, you
  3.     may modify it and use it for your own personal use, meaning that new
  4.     modified code and anything derived from it (such as exe files) doesn't
  5.     get distributed to anyone, unless you get my permission first.  Code
  6.     from this file, or code based on ideas from this file may be used with
  7.     other programs, provided that you give credit for it in the source code,
  8.     documentation, and 'about' windows or screens, if one exists, for the
  9.     programs using it.  Giving credit means something like this:
  10.  
  11.     Code from DMapEdit was used in this program
  12.  
  13.                               or
  14.  
  15.     Some code for this program was based on ideas presented in DMapEdit
  16.  
  17.     Whatever.  Just be sure to mention "DMapEdit" in such a way that it's
  18.     self-evident how it was useful to the new program, and be sure to have
  19.     "DMapEdit is a trademark of Jason Hoffoss" in the docs.  That's all..
  20. */
  21.  
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <conio.h>
  25. #include <graphics.h>
  26. #include <dos.h>
  27. #include <dir.h>
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <math.h>
  31. #include <ctype.h>
  32. #include <alloc.h>
  33. #include "dme.h"
  34.  
  35. #define MAX_ZOOM 7
  36.  
  37. int read_ini_file(int gmode, char *gname);
  38. void reconfig_mouse(void);
  39. void print_button(int button, char *name);
  40. void sw2_notice(void);
  41.  
  42. extern cur_box_color;
  43. extern old_mark_color;
  44.  
  45. int breakpoint=0; /* used for debugging */
  46. int bypass_sw=0; /* bypass the shareware notice message */
  47. int attempt_save=0; /* attempting to save after a fatal error */
  48. int mem_trace=0; /* track all memory calls to the log file */
  49. int sw_doom=0; /* is this shareware doom? */
  50. int flash_mode=1; /* use new style object hilighting */
  51. int backup=1; /* make backup files */
  52. int version=30; /* version number times 10 */
  53. int graph_on=0; /* graphics mode is on */
  54. int testmode=0; /* if in test mode */
  55. int grid=0; /* grid color/off */
  56. int roundoff=2; /* round off mouse (x,y) coords to multiple of 8 or 16 */
  57. int color_num; /* current hilight color */
  58. int points=0; /* display points mode size/off */
  59. int point_size=1; /* point size (same as points, or 1 if points is 0) */
  60. int things_on=1; /* size to draw things/off */
  61. int line_size=1; /* thickness of drawn lines */
  62. int midx, midy; /* center of screen coord */
  63. int mouse; /* is the mouse pointer visible? */
  64. int mousex, mousey; /* mouse screen coord */
  65. int crossx, crossy; /* mouse crosshare coord */
  66. int cross_on=1, cross_draw;
  67. int mouse_maxx, mouse_maxy; /* max mouse screen coord */
  68. int maxx, maxy; /* max screen coord */
  69. int cur_drag; /* # of whatever we are currently draging */
  70. int episode=1, mission=1; /* duh.. */
  71. int edit_mode=0; /* what are we editing now? */
  72. int color_scheme=0; /* method using to color walls */
  73. int mark_mask=0; /* marked items hilighting method */
  74. int flags_mask=7; /* display things bits */
  75. int flags_mask2=7; /* display things match exactly bits */
  76. int text_color=255; /* color to draw text */
  77. int editing_pwad=0; /* are we editing a pwad? */
  78. int systime; /* sync'ed hundred seconds count */
  79. int marked;
  80. uint v_size=0; /* # of vertexes */
  81. uint v_max=0; /* # of vertexes current memory block can hold */
  82. uint max_vertex=0; /* # of vertexes used by lines (below seg used ones) */
  83. uint l_size=0; /* # of linedefs */
  84. uint l_max=0;
  85. uint s_size=0; /* # of sidedefs */
  86. uint s_max=0;
  87. uint t_size=0; /* # of things */
  88. uint t_max=0;
  89. uint b_size=0; /* size of blockmap */
  90. uint n_size=0; /* size of nodes block */
  91. uint n_max=0;
  92. uint r_size=0; /* size of reject block */
  93. uint ss_size=0; /* # of special sectors */
  94. uint ss_max=0;
  95. uint sec_size=0; /* # of sectors */
  96. uint sec_max=0;
  97. uint seg_size=0; /* # of segments */
  98. uint seg_max=0;
  99. long entry_count; /* # entries left in directory structure */
  100. int button_status; /* current mouse buttons state */
  101. int true_button; /* the true mouse button that was pressed */
  102. int ignore_button=0; /* ignore mouse button down until released */
  103. int button_lock=0; /* mouse button locked on (from a keypress) */
  104. int left_button=1; /* function left mouse button performs */
  105. int middle_button=4;
  106. int right_button=2;
  107. int keypress; /* current key pressed on keyboard (ext +1000) */
  108. int scale=4; /* zoom factor, 0 is actually max zoomed in */
  109. int xoffset, yoffset; /* map to screen offsets */
  110. long dir_ptr; /* fseek position of directory in wad file */
  111. long dir_size; /* # of entries in the wad directory */
  112. long entry_ptr; /* fseek position of wad subfile */
  113. long entry_len; /* length of wad subfile */
  114. int thing_max; /* size of things list */
  115. int thing_name_size; /* length of longest name in list */
  116. int linetype_max;
  117. int linetype_name_size;
  118. int test_node=0; /* node being displayed (test mode only) */
  119. int tx1, tx2, tx3, tx4, ty1, ty2, ty3, ty4; /* test drawing points */
  120. char *help; /* help message id */
  121. FILE *fp, *fp2; /* general file pointers */
  122.  
  123. char pwad[80]="NEW.WAD"; /* working wad filename */
  124. char path[80]; /* program files path */
  125. char iwad[80]; /* path to doom.wad */
  126. unsigned char far doom_color[256]; /* table for doom color convertion */
  127. char *pwad1, *pwad2, *pwad3; /* pwad directory paths */
  128. int thing_types[96]; /* types of all known things */
  129. char far *thing_names[96]; /* descriptions of thing types */
  130. int thing_shapes[96]; /* shape to draw for this thing */
  131. int thing_rad[96]; /* thing's radius */
  132. int linetypes[133];
  133. char far *linetype_names[133];
  134. int adjvx[2000], adjvy[2000]; /* adjusted vertexes (screen coord) */
  135. int ll_size, llines[2000]; /* local lines (ones on the screen) */
  136. int far *mthings; /* marked thing list */
  137. int far *mvertexes; /* marked vertex list */
  138. int far *mlinedefs; /* marked linedef list */
  139. int far *msidedefs; /* marked sidedef list */
  140. int far *msectors; /* marked sector list */
  141. char mouse_save[164]; /* saved background of mouse cursor shape */
  142. char cross_save[29]; /* mouse crosshare image save buffer */
  143. char *point_ptr[5]; /* pointer to point size images */
  144. uint no_shapes, *shp_offsets; /* offset into shapes[] of shapes */
  145. char far *shapes; /* shape image data memory block */
  146. int lthing_count=0; /* # of lthings and memory flag */
  147. int *lthing_num; /* local things indexes */
  148. int *lthingx, *lthingy; /* local things screen coords */
  149. uint *lthing_offsets; /* local things shape table offsets */
  150. int far llist[LL_MAX];
  151.  
  152. struct { /* small radio button struct */
  153.     int num;
  154.     struct {
  155.         int x;
  156.         int y;
  157.         int on;
  158.         int status;
  159.     } pos[30];
  160. } far b;
  161.  
  162. struct { /* window struct */
  163.     int top;
  164.     int bottom;
  165.     int left;
  166.     int right;
  167.     int bars;
  168.     int okbar;
  169.     int canbar;
  170. } win;
  171.  
  172. struct { /* big buttons struct */
  173.     int num;
  174.     struct {
  175.         int x1;
  176.         int x2;
  177.         int y;
  178.     } pos[2];
  179. } bigb;
  180.  
  181. struct t_struct {
  182.     int x;
  183.     int y;
  184.     int angle;
  185.     int type;
  186.     int flags;
  187. } huge *things;
  188.  
  189. struct l_struct {
  190.     int v1;
  191.     int v2;
  192.     uint attrib;
  193.     int type;
  194.     int trig;
  195.     int sd1;
  196.     int sd2;
  197. } huge *linedefs;
  198.  
  199. struct s_struct {
  200.     int xoffset;
  201.     int yoffset;
  202.     char top[8];
  203.     char bottom[8];
  204.     char middle[8];
  205.     int sector;
  206. } huge *sidedefs;
  207.  
  208. struct v_struct {
  209.     int x;
  210.     int y;
  211. } huge *vertexes;
  212.  
  213. struct seg_struct {
  214.     int v1;
  215.     int v2;
  216.     uint angle;
  217.     int linedef;
  218.     int dir;
  219.     int dist;
  220. } huge *segs;
  221.  
  222. struct ss_struct {
  223.     int size;
  224.     int segptr;
  225. } huge *ssectors;
  226.  
  227. struct n_struct {
  228.     int x;
  229.     int y;
  230.     int dx;
  231.     int dy;
  232.     struct {
  233.         int y1;
  234.         int y2;
  235.         int x1;
  236.         int x2;
  237.     } node1;
  238.     struct {
  239.         int y1;
  240.         int y2;
  241.         int x1;
  242.         int x2;
  243.     } node2;
  244.     uint link1;
  245.     uint link2;
  246. } huge *nodes;
  247.  
  248. struct sec_struct {
  249.     int floor;
  250.     int ceiling;
  251.     char floor_name[8];
  252.     char ceiling_name[8];
  253.     int light;
  254.     int type;
  255.     int trig;
  256. } huge *sectors;
  257.  
  258. char huge *reject;
  259.  
  260. struct {
  261.     int xorigin;
  262.     int yorigin;
  263.     int xsize;
  264.     int ysize;
  265.     int offsets[9];
  266. } huge *blockmap;
  267.  
  268. int powers[] = { 4, 8, 16, 32, 64, 128, 256 };
  269. int xor_powers[] = { 0xfffc, 0xfff8, 0xfff0, 0xffe0, 0xffc0, 0xff80, 0xff00 };
  270. int scalers[] = { 1, 2, 4, 8, 16, 24, 36, 48 };
  271.  
  272. char crosshare[] = {
  273.     0x04, 0x00, 0x04, 0x00,
  274.     0x00, 0x81, 0x50, 0x81, 0x00,
  275.     0x81, 0x81, 0x50, 0x81, 0x81,
  276.     0x50, 0x50, 0x32, 0x50, 0x50,
  277.     0x81, 0x81, 0x50, 0x81, 0x81,
  278.     0x00, 0x81, 0x50, 0x81, 0x00 }; /* mouse crosshare image */
  279.  
  280. char point_image[] = {
  281.     0x02, 0x00, 0x02, 0x00, /* point size 1 */
  282.     0xff, 0xff, 0xff,
  283.     0xff, 0xff, 0xff,
  284.     0xff, 0xff, 0xff,
  285.  
  286.     0x04, 0x00, 0x04, 0x00, /* point size 2 */
  287.     0x00, 0xff, 0xff, 0xff, 0x00,
  288.     0xff, 0xff, 0xff, 0xff, 0xff,
  289.     0xff, 0xff, 0xff, 0xff, 0xff,
  290.     0xff, 0xff, 0xff, 0xff, 0xff,
  291.     0x00, 0xff, 0xff, 0xff, 0x00,
  292.  
  293.     0x06, 0x00, 0x06, 0x00, /* point size 3 */
  294.     0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
  295.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  296.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  297.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  298.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  299.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  300.     0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
  301.  
  302.     0x08, 0x00, 0x08, 0x00, /* point size 4 */
  303.     0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
  304.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  305.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  306.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  307.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  308.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  309.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  310.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  311.     0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
  312.  
  313.     0x0a, 0x00, 0x0a, 0x00, /* point size 5 */
  314.     0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
  315.     0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
  316.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  317.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  318.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  319.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  320.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  321.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  322.     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  323.     0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
  324.     0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 };
  325.  
  326. char *subfiles[10] = {
  327.     "THINGS",
  328.     "LINEDEFS",
  329.     "SIDEDEFS",
  330.     "VERTEXES",
  331.     "SEGS",
  332.     "SSECTORS",
  333.     "NODES",
  334.     "SECTORS",
  335.     "REJECT",
  336.     "BLOCKMAP" };
  337.  
  338. int main(int argc, char *argv[] )
  339. {
  340.     char gname[9], beta_msg[9];
  341.     int gmode;
  342.  
  343.     *beta_msg = 0;
  344.     if (BETA) strcpy(beta_msg, " (Beta)");
  345.  
  346. /*    printf("Doom Map Editor v%d.%d%s\n", version/10, version%10, beta_msg);*/
  347.     printf("Doom Map Editor v3.01\n");
  348.     gmode = general_setup(argc, argv, gname);
  349.     find_doom_wad();
  350.     load_textures();
  351.     load_pwad_startup();
  352.     init_graphics(gmode, gname);
  353.     init_mouse();
  354.     center_map();
  355.     draw_map();
  356.     sw2_notice();
  357.     sw_notice();
  358.     main_loop();
  359.     closegraph();
  360.     final_screen();
  361.     return;
  362. }
  363.  
  364. int general_setup(int argc, char *argv[], char *gname)
  365. {
  366.     char str[81], temp[31];
  367.     int i, j, k, gmode=2;
  368.     uint len;
  369.  
  370.     *iwad = 0;
  371.     help = NULL;
  372.     point_ptr[0] = point_image;
  373.     point_ptr[1] = point_image+13;
  374.     point_ptr[2] = point_image+42;
  375.     point_ptr[3] = point_image+95;
  376.     point_ptr[4] = point_image+180;
  377.  
  378.     t_size = l_size = s_size = v_size = seg_size = ss_size = n_size =
  379.         sec_size = r_size = b_size = 0;
  380.     unlink("memory.log");
  381.     make_lists();
  382.  
  383.     strcpy(path, argv[0] );
  384.     i = strlen(path);
  385.     while (i--)
  386.         if (path[i] == '\\')
  387.         {
  388.             path[i+1] = 0;
  389.             break;
  390.         }
  391.  
  392.     thing_max = 0;
  393.     thing_name_size = 0;
  394.     open_prog_file("itemlist.dme", "r");
  395.     while (fgets(str, 80, fp) != NULL)
  396.     {
  397.         char *name_ptr;
  398.  
  399.         if (thing_max == 96)
  400.             fatal_error("Item list is too big");
  401.         if (*str == '*' || *str == '\n') continue; /* skip this line */
  402.         sscanf(str, "%d,%d,%d,%n", &thing_types[thing_max],
  403.             &thing_shapes[thing_max], &thing_rad[thing_max], &i);
  404.         str[strlen(str)-1] = 0; /* trash the newline char */
  405.         name_ptr = &str[i];
  406.         j = strlen(name_ptr);
  407.         thing_names[thing_max] = get_farmem(j+1, "thing_names");
  408.         _fstrcpy(thing_names[thing_max], name_ptr);
  409.         if (j > thing_name_size)
  410.             thing_name_size = j;
  411.         thing_max++;
  412.     }
  413.     fclose(fp);
  414.  
  415.     linetype_max = 0;
  416.     open_prog_file("linetype.dme", "r");
  417.     while (fgets(str, 80, fp) != NULL)
  418.     {
  419.         char *name_ptr;
  420.  
  421.         if (*str == '*' || *str == '\n' ||
  422.             *str == '%') continue; /* skip this line */
  423.  
  424.         if (linetype_max == 133)
  425.             fatal_error("Linetype list is too big");
  426.  
  427.         sscanf(str, "%d,%n", &linetypes[linetype_max], &i);
  428.         str[strlen(str)-1] = 0; /* trash the newline char */
  429.         name_ptr = &str[i];
  430.         j = strlen(name_ptr);
  431.         linetype_names[linetype_max] = get_farmem(j+1, "linetype_names");
  432.         _fstrcpy(linetype_names[linetype_max], name_ptr);
  433.         if (j > linetype_name_size)
  434.             linetype_name_size = j;
  435.         linetype_max++;
  436.     }
  437.     fclose(fp);
  438.  
  439.     open_prog_file("shapes.dme", "rb");
  440.     fread(&no_shapes, sizeof(no_shapes), 1, fp);
  441.     fread(&len, sizeof(len), 1, fp);
  442.     shp_offsets = get_mem(no_shapes * 2, "shp_offsets");
  443.     fread(shp_offsets, 2, no_shapes, fp);
  444.     shapes = get_farmem(len, "shapes");
  445.     far_read(shapes, len);
  446.     fclose(fp);
  447.  
  448.     open_prog_file("coltable.dme", "rb");
  449.     far_read(doom_color, 256L);
  450.     fclose(fp);
  451.  
  452.     gmode = read_ini_file(gmode, gname);
  453.     strcpy(gname, "vesa");
  454.  
  455.     for (i=1; i<argc; i++)
  456.     {
  457.         if (*argv[i] == '-' || *argv[i] == '/')
  458.         {
  459.             argv[i]++;
  460.  
  461.             if (*argv[i] == 'v' || *argv[i] == 'V')
  462.             {
  463.                 argv[i]++;
  464.                 if (!isdigit(*argv[i]))
  465.                 {
  466.                     j = 0;
  467.                     while ((str[j] = argv[i][j]) != ',')
  468.                         j++;
  469.                     str[j] = str[8] = 0;
  470.                     strcpy(gname, str);
  471.                     argv[i] += j + 1;
  472.                 }
  473.                 gmode = atoi(argv[i]);
  474.                 continue;
  475.             }
  476.  
  477.             if (*argv[i] == 'x' || *argv[i] == 'X')
  478.                 bypass_sw++;
  479.  
  480.             if (!strcmp(argv[i], "memtrace"))
  481.             {
  482.                 mem_trace++;
  483.                 continue;
  484.             }
  485.  
  486.             if (!strcmp(argv[i], "test"))
  487.             {
  488.                 testmode++;
  489.                 continue;
  490.             }
  491.  
  492.             if (*argv[i] == 'i' || *argv[i] == 'I')
  493.             {
  494.                 if (strlen(argv[i]) > 80)
  495.                     *(argv[i] + 80) = 0;
  496.                 strcpy(iwad, argv[i]+1);
  497.             }
  498.         } else {
  499.             if (strlen(argv[i]) > 79)
  500.                 *(argv[i] + 79) = 0;
  501.             strcpy(pwad, argv[i]);
  502.             strupr(pwad);
  503.             if (strcmp(pwad + strlen(pwad) - 4, ".WAD"))
  504.             {
  505.                 if (strlen(pwad) > 75)
  506.                     pwad[75] = 0;
  507.                 strcat(pwad, ".WAD"); /* add extention if not there */
  508.             }
  509.             editing_pwad = 1;
  510.         }
  511.     }
  512.  
  513.     lthing_num = get_mem(1, "lthing_num"); /* dummy pointers */
  514.     lthingx = get_mem(1, "lthingx");
  515.     lthingy = get_mem(1, "lthingy");
  516.     lthing_offsets = get_mem(1, "lthing_offsets");
  517.  
  518.     return gmode;
  519. }
  520.  
  521. void main_loop(void)
  522. {
  523.     char name[13];
  524.     int chr, redraw;
  525.  
  526.     while (1)
  527.     {
  528.         chr = edit_branch();
  529.         redraw = map_keys(chr);
  530.         if (chr == 27)
  531.         {
  532.             window_text("Please confirm you wish to quit\n\n"
  533.                 "(be sure to save your map\t"
  534.                 "first, if you plan to)\t\n", 1);
  535.  
  536.             set_window_bars();
  537.             if (window_check() == -1)
  538.                 return;
  539.             redraw = 1;
  540.         }
  541.  
  542.         if (chr == -1)
  543.         {
  544.             window_text("Mode unavailable\n", 1);
  545.             chr = getkey();
  546.         }
  547.  
  548.         switch (chr)
  549.         {
  550.             case '0':
  551.             case '1':
  552.             case '2':
  553.             case '3':
  554.             case '4':
  555.             case '5':
  556.                 point_size = points = chr - '0';
  557.                 if (!points)
  558.                     point_size = 1;
  559.                 redraw = 1;
  560.                 break;
  561.  
  562.             case '<':
  563.             case ',':
  564.                 if (roundoff)
  565.                     roundoff--;
  566.                 redraw = 1;
  567.                 break;
  568.  
  569.             case '>':
  570.             case '.':
  571.                 if (roundoff < 6)
  572.                     roundoff++;
  573.                 redraw = 1;
  574.                 break;
  575.  
  576.             case 1059: /* F1 */
  577.                 edit_mode = 0;
  578.                 points = 0;
  579.                 things_on = scale>2 ? 2 : 1;
  580.                 redraw = 1;
  581.                 break;
  582.  
  583.             case 1060: /* F2 */
  584.                 edit_mode = 2;
  585.                 points = point_size;
  586.                 things_on = 0;
  587.                 redraw = 1;
  588.                 break;
  589.  
  590.             case 1061: /* F3 */
  591.                 edit_mode = 4;
  592.                 points = point_size;
  593.                 things_on = 0;
  594.                 redraw = 1;
  595.                 break;
  596.  
  597.             case 1062: /* F4 */
  598.                 edit_mode = 7;
  599.                 points = 0;
  600.                 things_on = 0;
  601.                 redraw = 1;
  602.                 break;
  603.  
  604.             case 'c':
  605.                 change_maps(0);
  606.                 redraw = 1;
  607.                 break;
  608.  
  609.             case 8: /* backspace */
  610.                 unmark_all();
  611.                 break;
  612.  
  613.             case 'n':
  614.                 clear_map1();
  615.                 redraw = 1;
  616.                 break;
  617.  
  618.             case 't':
  619.                 if (things_on++ == 2)
  620.                     things_on = -1;
  621.                 if (!edit_mode && !things_on)
  622.                     things_on++;
  623.                 redraw = 1;
  624.                 break;
  625.  
  626.             case '\\':
  627.                 line_size ^= 2;
  628.                 redraw = 1;
  629.                 break;
  630.  
  631.             case 'l':
  632.                 if (!get_wadname("Load", "from"))
  633.                     change_maps(1);
  634.                 redraw = 1;
  635.                 break;
  636.  
  637.             case '\t':
  638.                 reconfig_mouse();
  639.                 redraw = 1;
  640.                 break;
  641.  
  642.             case 's':
  643.                 save_wad_map(1);
  644.                 break;
  645.  
  646.             case 1038: /* Alt-L, load working wad */
  647.                 if (editing_pwad)
  648.                     load_wad_map(0);
  649.                 else if (!get_wadname("Load", "from"))
  650.                     change_maps(1);
  651.                 redraw = 1;
  652.                 break;
  653.  
  654.             case 1019: /* Alt-R, reload IWAD */
  655.                 load_wad_map(1);
  656.                 redraw = 1;
  657.                 break;
  658.  
  659.             case 1031: /* Alt-S, save working wad */
  660.                 save_wad_map(0);
  661.                 break;
  662.  
  663.             case 1029: /* Alt-W, save to IWAD */
  664.                 save_wad_map(1);
  665.                 break;
  666.  
  667.             case 1120: /* Alt-1 */
  668.             case 1121:
  669.             case 1122:
  670.                 color_scheme = chr - 1120;
  671.                 redraw = 1;
  672.                 break;
  673.  
  674.             case 1067: /* F9 */
  675.                 misc_options();
  676.                 redraw = 1;
  677.                 break;
  678.  
  679.             case 1068: /* F10 */
  680.                 if (testmode)
  681.                     edit_mode = 100;
  682.                 redraw = 1;
  683.                 break;
  684.  
  685.             case 1133: /* F11 */
  686.                 test_node = n_size - 1;
  687.                 if (testmode)
  688.                     edit_mode = 101;
  689.                 redraw = 1;
  690.                 break;
  691.  
  692.             case 1134: /* F12 */
  693.                 if (testmode)
  694.                     edit_mode = 102;
  695.                 redraw = 1;
  696.                 break;
  697.  
  698.             case '_':
  699.                 center_map();
  700.                 redraw = 1;
  701.                 break;
  702.  
  703.             case '?':
  704.                 gen_help();
  705.                 redraw = 1;
  706.                 break;
  707.  
  708.             case 'f':
  709.                 set_flags_mask();
  710.                 redraw = 1;
  711.                 break;
  712.  
  713.             case 'z':
  714.                 statistics();
  715.                 redraw = 1;
  716.                 break;
  717.  
  718.             case 1047:
  719.                 version_info();
  720.                 break;
  721.  
  722.             case 'g':
  723.                 grid++;
  724.                 if (grid == 1)
  725.                     grid = 252;
  726.                 if (grid == 255)
  727.                     grid = 0;
  728.                 redraw = 1;
  729.                 break;
  730.  
  731.             case 1049: /* Alt-N */
  732.                 generate_nodes();
  733.                 redraw = 1;
  734.                 break;
  735.  
  736.             case '~':
  737.                 if (testmode)
  738.                     block_test();
  739.                 break;
  740.         }
  741.  
  742.         if (redraw)
  743.         {
  744.             draw_map();
  745.             await_release();
  746.         }
  747.     }
  748. }
  749.  
  750. void set_flags_mask(void)
  751. {
  752.     int i, button, f, f2;
  753.     int mask[] = { 0x1, 0x2, 0x4, 0x10 };
  754.  
  755.     f = flags_mask;
  756.     f2 = flags_mask2;
  757.  
  758.     window_text("Display things for:\t\n"
  759.         "Skill levels 1 & 2. @ @\n"
  760.         "Skill level 3...... @ @\n"
  761.         "Skill level 4...... @ @\n"
  762.         "Deathmatch mode.... @ @\n\n", 1);
  763.  
  764.     set_window_bars();
  765.     for (i=0; i<4; i++)
  766.     {
  767.         b.pos[i*2].on = f & mask[i];
  768.         b.pos[i*2+1].on = f2 & mask[i];
  769.     }
  770.  
  771.     while ((button = window_check()) > -1)
  772.     {
  773.         if (button & 1)
  774.         {
  775.             f2 ^= mask[button / 2];
  776.             b.pos[button].on = f2 & mask[button / 2];
  777.         } else {
  778.             f ^= mask[button / 2];
  779.             b.pos[button].on = f & mask[button / 2];
  780.         }
  781.     }
  782.  
  783.     if (button == -1)
  784.     {
  785.         flags_mask = f;
  786.         flags_mask2 = f2;
  787.     }
  788.     return;
  789. }
  790.  
  791. void gen_help(void)
  792. {
  793.     window_text("Global commands summary\t\n"
  794.         "F1: Select thing edit mode     Escape: Quit back to dos\n"
  795.         "F2: Select vertex edit mode    Arrows: Scroll map around\n"
  796.         "F3: Select line edit mode\n"
  797.         "F4: Select sector edit mode     Alt-W: Write map to the IWAD\n"
  798.         "F9: Advanced/misc options       Alt-R: Reload map from the IWAD\n"
  799.         " S: Save map to PWAD file       Alt-S: Save map to a PWAD file\n"
  800.         " L: Load map from PWAD file     Alt-L: Load map from a PWAD file\n"
  801.         " C: Change episode & mission #    0-5: Change vertex display size\n"
  802.         " F: Change thing display masks      M: Mark object\n"
  803.         " N: Make new map from scratch       T: Change thing icon size\n"
  804.         " Z: Statistics                      \\: Change line display size\n"
  805.         " +: Zoom in                         -: Zoom out\n"
  806.         " G: Change grid intensity\n\n\n"
  807.         "Editing modes specific commands\t\n"
  808.         "Enter: Copy selected Thing to default Thing (Thing edit mode)\n"
  809.         "    F: Flip line (Line edit mode)\n"
  810.         "Alt-F: Flip line and sidedefs (Line edit mode)\n"
  811.         "    B: Enter Blend mode (Sector edit mode)\n\n\n"
  812.         "Mouse Buttons:\t\n"
  813.         "Left - Move/Add     Mid - Edit     Right - Delete\t"
  814.         "(Ins key)        (Spacebar)       (Del key)\t", 1);
  815.  
  816.     while (!mouse_check())
  817.         if (keypress)
  818.             break;
  819.  
  820.     return;
  821. }
  822.  
  823. void clear_map1(void)
  824. {
  825.     window_text("New map\t\n"
  826.         "This function will erase the current\n"
  827.         "map and start you off with a blank\n"
  828.         "map.  Are you sure this is what you\n"
  829.         "want to do?\n\n", 1);
  830.  
  831.     set_window_bars();
  832.     if (window_check() == -1)
  833.         clear_map();
  834.     return;
  835. }
  836.  
  837. void clear_map(void)
  838. {
  839.     unmark_all();
  840.     if (t_max)
  841.         free_farmem(things, "Things");
  842.     if (l_max)
  843.         free_farmem(linedefs, "Linedefs");
  844.     if (s_max)
  845.         free_farmem(sidedefs, "Sidedefs");
  846.     if (v_max)
  847.         free_farmem(vertexes, "Vertexes");
  848.     if (seg_max)
  849.         free_farmem(segs, "Segments");
  850.     if (ss_max)
  851.         free_farmem(ssectors, "Sub Sectors");
  852.     if (n_max)
  853.         free_farmem(nodes, "Nodes");
  854.     if (sec_max)
  855.         free_farmem(sectors, "Sectors");
  856.     if (r_size)
  857.         free_farmem(reject, "Reject");
  858.     if (b_size)
  859.         free_farmem(blockmap, "Blockmap");
  860.  
  861.     t_size = l_size = s_size = v_size = seg_size = ss_size = n_size =
  862.     sec_size = r_size = b_size = t_max = l_max = s_max = v_max = seg_max =
  863.     ss_max = n_max = sec_max = max_vertex = 0;
  864.     center_map();
  865. }
  866.  
  867. int edit_branch(void)
  868. {
  869.     if (edit_mode == 0) return thing_edit();
  870.     if (edit_mode == 1) return thing_drag();
  871.     if (edit_mode == 2) return vertex_edit();
  872.     if (edit_mode == 3) return vertex_drag();
  873.     if (edit_mode == 4) return line_edit();
  874.     if (edit_mode == 5) return line_drag1();
  875.     if (edit_mode == 6) return line_drag2();
  876.     if (edit_mode == 7 ||
  877.         edit_mode == 8) return sector_edit();
  878.     if (edit_mode == 100) return seg_test();
  879.     if (edit_mode == 101) return node_test2();
  880.     if (edit_mode == 102) return node_test();
  881.     return getkey();
  882. }
  883.  
  884. int map_keys(int key)
  885. {
  886.     int redraw=1, fix=0;
  887.  
  888.     switch (key)
  889.     {
  890.         case '+':
  891.         case '=':
  892.             if (scale > 0)
  893.             {
  894.                 scale--;
  895.                 fix++;
  896.             }
  897.             break;
  898.         case '-':
  899.             if (scale < MAX_ZOOM)
  900.             {
  901.                 scale++;
  902.                 fix++;
  903.             }
  904.             break;
  905.         case 1072: /* up */
  906.             yoffset += 100 * scalers[scale] / 2;
  907.             break;
  908.         case 1080: /* down */
  909.             yoffset -= 100 * scalers[scale] / 2;
  910.             break;
  911.         case 1075: /* left */
  912.             xoffset -= 100 * scalers[scale] / 2;
  913.             break;
  914.         case 1077: /* right */
  915.             xoffset += 100 * scalers[scale] / 2;
  916.             break;
  917.         case 1071: /* up-left (Home) */
  918.             yoffset += 100 * scalers[scale] / 2;
  919.             xoffset -= 100 * scalers[scale] / 2;
  920.             break;
  921.         case 1073: /* up-right (PgUp) */
  922.             yoffset += 100 * scalers[scale] / 2;
  923.             xoffset += 100 * scalers[scale] / 2;
  924.             break;
  925.         case 1079: /* down-left (End) */
  926.             yoffset -= 100 * scalers[scale] / 2;
  927.             xoffset -= 100 * scalers[scale] / 2;
  928.             break;
  929.         case 1081: /* down-right (PgDn) */
  930.             yoffset -= 100 * scalers[scale] / 2;
  931.             xoffset += 100 * scalers[scale] / 2;
  932.             break;
  933.         case 'x':
  934.             cross_on = !cross_on;
  935.         default:
  936.             redraw = 0;
  937.     }
  938.  
  939.     if (fix)
  940.     {
  941.         if (things_on > 0)
  942.             things_on = scale>2 ? 2 : 1;
  943.  
  944.         point_size = 4 - scale;
  945.         if (point_size < 1)
  946.             point_size = 1;
  947.  
  948.         points = 0;
  949.         if (edit_mode >= 2 && edit_mode < 7)
  950.             points = point_size;
  951.     }
  952.     return redraw;
  953. }
  954.  
  955. void draw_vertex(int num, int color, int size)
  956. {
  957.     char image[125];
  958.     int i, x, y;
  959.  
  960.     if (!size)
  961.         size = 1;
  962.  
  963.     x = adjvx[num];
  964.     y = adjvy[num];
  965.  
  966.     if (x < size ||
  967.          y < size ||
  968.          x > maxx - (size * 2) ||
  969.          y > maxy - (size * 2)) return;
  970.  
  971.     getimage(x-size, y-size, x+size, y+size, image);
  972.     for (i=0; i<121; i++)
  973.         if (point_ptr[size-1][i+4])
  974.             image[i+4] = color;
  975.  
  976.     putimage(x-size, y-size, image, 0);
  977.     return;
  978. }
  979.  
  980. int re_x(void)
  981. {
  982.     int x;
  983.  
  984.     x = mouse_x;
  985.     if (roundoff)
  986.     {
  987.         x += powers[roundoff-1];
  988.         x &= xor_powers[roundoff];
  989.     }
  990.     return x;
  991. }
  992.  
  993. int re_y(void)
  994. {
  995.     int y;
  996.  
  997.     y = mouse_y;
  998.     if (roundoff)
  999.     {
  1000.         y += powers[roundoff-1];
  1001.         y &= xor_powers[roundoff];
  1002.     }
  1003.     return y;
  1004. }
  1005.  
  1006. int add_vertex(void) /* add vertex for line use */
  1007. {
  1008.     int i, x, y;
  1009.  
  1010.     x = re_x();
  1011.     y = re_y();
  1012.     for (i=0; i<max_vertex; i++)
  1013.         if (x == vertexes[i].x && y == vertexes[i].y)
  1014.             return i;
  1015.  
  1016.     if (n_max)
  1017.         free_farmem(nodes, "Nodes");
  1018.     if (ss_max)
  1019.         free_farmem(ssectors, "Sub Sectors");
  1020.     if (seg_max)
  1021.         free_farmem(segs, "Segments");
  1022.     n_size = ss_size = seg_size = n_max = ss_max = seg_max = 0;
  1023.  
  1024.     if (max_vertex == v_max)
  1025.     {
  1026.         void far *ptr;
  1027.  
  1028.         if (v_max)
  1029.             ptr = resize_farmem(vertexes, (v_max+20) * sizeof(struct v_struct),
  1030.                 "Vertexes");
  1031.         else
  1032.             ptr = get_farmem(20 * sizeof(struct v_struct), "Vertexes");
  1033.  
  1034.         if (!ptr)
  1035.             return -1;
  1036.         vertexes = ptr;
  1037.         v_max += 20;
  1038.     }
  1039.  
  1040.     vertexes[max_vertex].x = x;
  1041.     vertexes[max_vertex].y = y;
  1042.  
  1043.     x = adjustx(x);
  1044.     y = adjusty(y);
  1045.     if (x < 0) x = 0;
  1046.     if (y < 0) y = 0;
  1047.     if (x > maxx) x = maxx;
  1048.     if (y > maxy) y = maxy;
  1049.  
  1050.     adjvx[max_vertex] = x;
  1051.     adjvy[max_vertex] = y;
  1052.     v_size = max_vertex++;
  1053.     return v_size++;
  1054. }
  1055.  
  1056. void del_vertex(int num) /* delete vertex and reroute lines to it */
  1057. {
  1058.     int i, v, max, nearv, kill_line, linesto[50];
  1059.     double nearest, dist, dx, dy;
  1060.  
  1061.     if (n_max)
  1062.         free_farmem(nodes, "Nodes");
  1063.     if (ss_max)
  1064.         free_farmem(ssectors, "Sub Sectors");
  1065.     if (seg_max)
  1066.         free_farmem(segs, "Segments");
  1067.     n_size = ss_size = seg_size = n_max = ss_max = seg_max = 0;
  1068.  
  1069.     for (i=0, max=0; i<l_size; i++)
  1070.     {
  1071.         if (linedefs[i].v1 == num)
  1072.             linesto[max++] = i;
  1073.         if (linedefs[i].v2 == num)
  1074.             linesto[max++] = -i;
  1075.     }
  1076.     if (max)
  1077.     {
  1078.         nearest = 3.2e6; /* make it easily the farthest dist.. */
  1079.         for (i=0; i<max; i++)
  1080.         {
  1081.             if (linesto[i] > 0)
  1082.                 v = linedefs[linesto[i]].v2;
  1083.             else
  1084.                 v = linedefs[-linesto[i]].v1;
  1085.             dx = vertexes[num].x - vertexes[v].x;
  1086.             dy = vertexes[num].y - vertexes[v].y;
  1087.             dist = sqrt(dx * dx + dy * dy);
  1088.             if (dist < nearest)
  1089.             {
  1090.                 nearest = dist;
  1091.                 nearv = v;
  1092.             }
  1093.         }
  1094.  
  1095.         for (i=0; i<max; i++)
  1096.         {
  1097.             if (linesto[i] > 0)
  1098.             {
  1099.                 if (linedefs[linesto[i]].v2 == nearv)
  1100.                 {
  1101.                     kill_line = linesto[i];
  1102.                     continue;
  1103.                 }
  1104.                 linedefs[linesto[i]].v1 = nearv;
  1105.             } else {
  1106.                 if (linedefs[-linesto[i]].v1 == nearv)
  1107.                 {
  1108.                     kill_line = -linesto[i];
  1109.                     continue;
  1110.                 }
  1111.                 linedefs[-linesto[i]].v2 = nearv;
  1112.             }
  1113.         }
  1114.         del_line(kill_line);
  1115.     }
  1116.  
  1117.     for (i=num; i<v_size-1; i++)
  1118.         vertexes[i] = vertexes[i+1];
  1119.  
  1120.     for (i=0; i<l_size; i++)
  1121.     {
  1122.         if (linedefs[i].v1 > num)
  1123.             linedefs[i].v1--;
  1124.         if (linedefs[i].v2 > num)
  1125.             linedefs[i].v2--;
  1126.     }
  1127.  
  1128.     v_size = --max_vertex;
  1129.     return;
  1130. }
  1131.  
  1132. /* flip the line around if the only sidedef is on the wrong side */
  1133.  
  1134. void flip_line(int num)
  1135. {
  1136.     int temp, sd1, sd2, count1, count2;
  1137.  
  1138.     if ((sd2 = linedefs[num].sd2) != -1 && linedefs[num].sd1 == -1)
  1139.     {
  1140.         temp = linedefs[num].v1;
  1141.         linedefs[num].v1 = linedefs[num].v2;
  1142.         linedefs[num].v2 = temp;
  1143.  
  1144.         linedefs[num].sd1 = sd2;
  1145.         linedefs[num].sd2 = -1;
  1146.     }
  1147.  
  1148.     if ((sd1 = linedefs[num].sd1) != -1 && sd2 != -1)
  1149.     {
  1150.         count1 = count2 = 0;
  1151.  
  1152.         if (sidedefs[sd1].top[0] != '-')
  1153.             count1++;
  1154.         if (sidedefs[sd1].middle[0] != '-')
  1155.             count1++;
  1156.         if (sidedefs[sd1].bottom[0] != '-')
  1157.             count1++;
  1158.  
  1159.         if (sidedefs[sd2].top[0] != '-')
  1160.             count2++;
  1161.         if (sidedefs[sd2].middle[0] != '-')
  1162.             count2++;
  1163.         if (sidedefs[sd2].bottom[0] != '-')
  1164.             count2++;
  1165.  
  1166.         if (count2 > count1) /* seems right sidedef is the major one */
  1167.         {
  1168.             temp = linedefs[num].v1;
  1169.             linedefs[num].v1 = linedefs[num].v2;
  1170.             linedefs[num].v2 = temp;
  1171.  
  1172.             linedefs[num].sd1 = sd2;
  1173.             linedefs[num].sd2 = sd1;
  1174.         }
  1175.     }
  1176.     return;
  1177. }
  1178.  
  1179. int add_sidedef(int num)
  1180. {
  1181.     struct s_struct default_def = { 0, 0, "-", "-", "BROWN1", -1 };
  1182.  
  1183.     if (s_size == s_max)
  1184.     {
  1185.         void far *ptr;
  1186.  
  1187.         if (s_max)
  1188.             ptr = resize_farmem(sidedefs, (s_max+20) * sizeof(struct s_struct),
  1189.                 "Sidedefs");
  1190.         else
  1191.             ptr = get_farmem(20 * sizeof(struct s_struct), "Sidedefs");
  1192.  
  1193.         if (!ptr)
  1194.             return -1;
  1195.         sidedefs = ptr;
  1196.         s_max += 20;
  1197.     }
  1198.  
  1199.     if (num == -1)
  1200.         sidedefs[s_size] = default_def;
  1201.     else
  1202.         sidedefs[s_size] = sidedefs[num];
  1203.     return s_size++;
  1204. }
  1205.  
  1206. int between(int x1, int x2, int x3) /* determine if x1 is between x2 & x3 */
  1207. {
  1208.     int temp;
  1209.  
  1210.     if (x2 > x3)
  1211.     {
  1212.         temp = x2;
  1213.         x2 = x3;
  1214.         x3 = temp;
  1215.     }
  1216.     return (x1 >= x2 && x1 <= x3);
  1217. }
  1218.  
  1219. void del_line(int num)
  1220. {
  1221.     int i, sd1, sd2, sec1, sec2;
  1222.  
  1223.     sd1 = linedefs[num].sd1;
  1224.     sd2 = linedefs[num].sd2;
  1225.  
  1226.     if (sd1 != -1 && sd2 != -1 && (sec1 = sidedefs[sd1].sector) != -1 &&
  1227.         (sec2 = sidedefs[sd2].sector) != -1 && sec1 != sec2)
  1228.     { /* merge sectors */
  1229.         for (i=0; i<s_size; i++)
  1230.         {
  1231.             if (sidedefs[i].sector == sec1)
  1232.                 sidedefs[i].sector = sec2;
  1233.             if (sidedefs[i].sector > sec1)
  1234.                 sidedefs[i].sector--;
  1235.         }
  1236.         if (sec1 + 1 < sec_size)
  1237.             for (i=sec1; i<sec_size-1; i++)
  1238.                 sectors[i] = sectors[i+1];
  1239.         sec_size--;
  1240.     }
  1241.     if (sd1 != -1)
  1242.         del_sidedef(sd1); /* this could make sd2 != sidedef2 */
  1243.     if (sd2 != -1)
  1244.         del_sidedef(linedefs[num].sd2); /* so do it this way */
  1245.  
  1246.     for (i=num; i<l_size-1; i++)
  1247.         linedefs[i] = linedefs[i+1];
  1248.     l_size--;
  1249.     return;
  1250. }
  1251.  
  1252. void del_sidedef(int num)
  1253. {
  1254.     int i;
  1255.  
  1256.     for (i=num; i<s_size-1; i++)
  1257.         sidedefs[i] = sidedefs[i+1];
  1258.     s_size--;
  1259.     for (i=0; i<l_size; i++)
  1260.     {
  1261.         if (linedefs[i].sd1 == num)
  1262.             linedefs[i].sd1 = -1;
  1263.         if (linedefs[i].sd2 == num)
  1264.             linedefs[i].sd2 = -1;
  1265.         if (linedefs[i].sd1 > num) /* fix linedef pointers */
  1266.             linedefs[i].sd1--;
  1267.         if (linedefs[i].sd2 > num)
  1268.             linedefs[i].sd2--;
  1269.     }
  1270.     return;
  1271. }
  1272.  
  1273. int draw_time_graph(int y)
  1274. {
  1275.     int x;
  1276.  
  1277.     x = (win.right + win.left) / 2 - 50;
  1278.     rectangle(x-1, y-1, x+101, y+8);
  1279.     return x;
  1280. }
  1281.  
  1282. void time_graph(ulong num, ulong max, int x, int y)
  1283. {
  1284.     int i, j, xx, yy, percent;
  1285.  
  1286.     percent = num * 100 / max;
  1287.     xx = x + percent + 1;
  1288.     yy = y + 8;
  1289.  
  1290.     if (percent)
  1291.         for (i=x; i<xx; i++)
  1292.             for (j=y; j<yy; j++)
  1293.                 putpixel(i, j, 96);
  1294.     return;
  1295. }
  1296.  
  1297. void reset_time_graph(ulong num, ulong max, int x, int y)
  1298. {
  1299.     int i, j, xx, yy, percent;
  1300.  
  1301.     percent = num * 100 / max;
  1302.     xx = x + percent + 1;
  1303.     yy = y + 8;
  1304.  
  1305.     if (percent)
  1306.         for (i=x; i<xx; i++)
  1307.             for (j=y; j<yy; j++)
  1308.                 putpixel(i, j, 252);
  1309.     return;
  1310. }
  1311.  
  1312. void change_maps(int mode)
  1313. {
  1314.     char maps[27];
  1315.     int i, button, btn=0, temp, count;
  1316.  
  1317.     struct
  1318.     {
  1319.         long ptr;
  1320.         long len;
  1321.         char fname[8];
  1322.     } dir;
  1323.  
  1324.     button = (episode - 1) * 9 + (mission - 1);
  1325.     for (i=0; i<27; i++)
  1326.         maps[i] = -1;
  1327.  
  1328.     open_wad(iwad, "rb");
  1329.     for (i=0; i<dir_size; i++)
  1330.     {
  1331.         if (!fread(&dir, sizeof(dir), 1, fp))
  1332.             dir_error();
  1333.         if (dir.len)
  1334.             continue;
  1335.         if (dir.fname[0] != 'E')
  1336.             continue;
  1337.         if (dir.fname[2] != 'M')
  1338.             continue;
  1339.         if (dir.fname[4])
  1340.             continue; /* at this point, we know it's a map header */
  1341.         temp = (dir.fname[1] - '1') * 9 + (dir.fname[3] - '1');
  1342.         if (temp > 26)
  1343.             dir_error(); /* just in case, cause you never know */
  1344.         maps[temp] = -2;
  1345.     }
  1346.     fclose(fp);
  1347.  
  1348.     if (editing_pwad)
  1349.     {
  1350.         if (open_wad(pwad, "rb"))
  1351.         {
  1352.             error("Can't open \"%s\"", pwad);
  1353.             editing_pwad = 0;
  1354.             return;
  1355.         }
  1356.  
  1357.         for (i=0; i<dir_size; i++)
  1358.         {
  1359.             if (!fread(&dir, sizeof(dir), 1, fp))
  1360.                 dir_error();
  1361.             if (dir.len)
  1362.                 continue;
  1363.             if (dir.fname[0] != 'E')
  1364.                 continue;
  1365.             if (dir.fname[2] != 'M')
  1366.                 continue;
  1367.             if (dir.fname[4])
  1368.                 continue; /* at this point, we know it's a map header */
  1369.             temp = (dir.fname[1] - '1') * 9 + (dir.fname[3] - '1');
  1370.             if (temp > 26)
  1371.                 dir_error(); /* just in case, cause you never know */
  1372.             maps[temp] = 0;
  1373.         }
  1374.         fclose(fp);
  1375.     } else
  1376.         for (i=0; i<27; i++)
  1377.             if (maps[i] == -2)
  1378.                 maps[i] = 0;
  1379.  
  1380.     if (mode == 1)
  1381.     {
  1382.         for (i=count=0; i<27; i++)
  1383.             if (!maps[i])
  1384.                 if (!count++)
  1385.                     button = i;
  1386.         if (count == 1)
  1387.             goto rtn;
  1388.     }
  1389.  
  1390.     window_text1("Mission\t\n"
  1391.         "E    1 2 3 4 5 6 7 8 9   \n"
  1392.         "p\n"
  1393.         "i  1 @ @ @ @ @ @ @ @ @\n"
  1394.         "s\n"
  1395.         "o  2 @ @ @ @ @ @ @ @ @\n"
  1396.         "d\n"
  1397.         "e  3 @ @ @ @ @ @ @ @ @\n\n"
  1398.         "[Load]\t\n", 1, 0, 0);
  1399.  
  1400.     for (i=0; i<27; i++)
  1401.         b.pos[i].status = maps[i];
  1402.     draw_buttons();
  1403.     set_window_bars();
  1404.  
  1405.     if (maps[button] != -1)
  1406.         b.pos[button].on = 1;
  1407.     while ((btn = window_check()) > -1)
  1408.     {
  1409.         b.pos[button].on = 0;
  1410.         b.pos[btn].on = 1;
  1411.         button = btn;
  1412.     }
  1413.  
  1414. rtn:
  1415.     if (btn == -99)
  1416.         return;
  1417.  
  1418.     episode = button / 9 + 1;
  1419.     mission = button % 9 + 1;
  1420.     if (btn == -1)
  1421.         return;
  1422.  
  1423.     load_wad_map(0);
  1424.     center_map();
  1425.     return;
  1426. }
  1427.  
  1428. void mouse_on(void)
  1429. {
  1430.     char msg[30];
  1431.     int x, y, i, z;
  1432.  
  1433.     setviewport(0, 0, maxx, maxy, 1);
  1434.     getimage(mousex-1, mousey-1, mousex+8, mousey+14, mouse_save);
  1435.     putimage(mousex-1, mousey-1, shapes, 2); /* mouse mask */
  1436.     putimage(mousex-1, mousey-1, shapes+shp_offsets[2+true_button], 3);
  1437.  
  1438.     x = re_x();
  1439.     y = re_y();
  1440.     crossx = adjustx(x) - 2;
  1441.     crossy = adjusty(y) - 2;
  1442.  
  1443.     cross_draw = 0;
  1444.     if (cross_on && crossx >= 0 && crossy >= 0 && crossx < maxx-3 &&
  1445.         crossy < maxy-3)
  1446.     {
  1447.         cross_draw++;
  1448.         getimage(crossx, crossy, crossx+4, crossy+4, cross_save);
  1449.         for (i=0; i<29; i++)
  1450.         {
  1451.             z = crosshare[i];
  1452.             if (!z)
  1453.                 z = cross_save[i];
  1454.             msg[i] = z;
  1455.         }
  1456.         putimage(crossx, crossy, msg, 0);
  1457.     }
  1458.  
  1459.     sprintf(msg, "(%d,%d)          ", x, y);
  1460.     msg[15] = 0;
  1461.     text(0, -1, msg);
  1462.     mouse = 1;
  1463.     return;
  1464. }
  1465.  
  1466. void mouse_redraw(void)
  1467. {
  1468.     if (!mouse)
  1469.         mouse_on();
  1470.     else {
  1471.         setviewport(0, 0, maxx, maxy, 1);
  1472.         putimage(mousex-1, mousey-1, shapes, 2); /* mouse mask */
  1473.         putimage(mousex-1, mousey-1, shapes+shp_offsets[2+true_button], 3);
  1474.     }
  1475.     return;
  1476. }
  1477.  
  1478. void mouse_off(void)
  1479. {
  1480.     if (cross_draw)
  1481.         putimage(crossx, crossy, cross_save, 0);
  1482.     putimage(mousex-1, mousey-1, mouse_save, 0);
  1483.     mouse = 0;
  1484.     return;
  1485. }
  1486.  
  1487. int mouse_check(void)
  1488. {
  1489.     int newx, newy;
  1490.     union REGS regs;
  1491.  
  1492.     if (!mouse)
  1493.         mouse_on();
  1494.     regs.x.ax = 11; /* read motion counters */
  1495.     int86(0x33, ®s, ®s);
  1496.     newx = mousex + regs.x.cx;
  1497.     newy = mousey + regs.x.dx;
  1498.  
  1499.     if (newx < 1) newx = 1;
  1500.     if (newy < 1) newy = 1;
  1501.     if (newx > mouse_maxx) newx = mouse_maxx;
  1502.     if (newy > mouse_maxy) newy = mouse_maxy;
  1503.     if (newx != mousex || newy != mousey)
  1504.     {
  1505.         mouse_off();
  1506.         mousex = newx;
  1507.         mousey = newy;
  1508.         mouse_on();
  1509.     }
  1510.  
  1511.     regs.x.ax = 5; /* read button status */
  1512.     regs.x.bx = 1;
  1513.     int86(0x33, ®s, ®s);
  1514.     if (regs.x.ax != true_button)
  1515.     {
  1516.         true_button = regs.x.ax;
  1517.         mouse_off();
  1518.         mouse_on(); /* redraw with button indication */
  1519.     }
  1520.  
  1521.     if (ignore_button)
  1522.     {
  1523.         if (ignore_button & true_button)
  1524.             true_button &= ~ignore_button;
  1525.         else
  1526.             ignore_button = 0;
  1527.     }
  1528.  
  1529.     button_status = 0;
  1530.     if (true_button & 0x1)
  1531.         button_status = left_button;
  1532.     if (true_button & 0x2)
  1533.         button_status |= right_button;
  1534.     if (true_button & 0x4)
  1535.         button_status |= middle_button;
  1536.  
  1537.     if (button_status)
  1538.         button_lock = 0;
  1539.  
  1540.     keypress = 0;
  1541.     if (kbhit())
  1542.     {
  1543.         keypress = getkey();
  1544.         if (button_lock)
  1545.             button_lock = keypress = 0; /* turn off lock */
  1546.  
  1547.         switch (keypress)
  1548.         {
  1549.             case 1082: /* insert key */
  1550.                 button_status |= 0x1; /* same as left mouse button */
  1551.                 keypress = 0;
  1552.                 break;
  1553.             case 1162: /* alt-insert */
  1554.                 button_lock = 0x1;
  1555.                 keypress = 0;
  1556.                 break;
  1557.             case 1083: /* delete key */
  1558.                 button_status |= 0x2; /* same as right mouse button */
  1559.                 keypress = 0;
  1560.                 break;
  1561.             case ' ': /* space bar, of course */
  1562.                 button_status |= 0x4; /* same as middle mouse button */
  1563.                 keypress = 0;
  1564.                 break;
  1565.             case 'm':
  1566.             case 'M':
  1567.                 button_status |= 0x8;
  1568.                 keypress = 0;
  1569.                 break;
  1570.             case 1050:
  1571.                 button_lock = 0x8;
  1572.                 keypress = 0;
  1573.                 break;
  1574.         }
  1575.     }
  1576.     button_status |= button_lock;
  1577.     return button_status;
  1578. }
  1579.  
  1580. void reconfig_mouse(void)
  1581. {
  1582.     int button, new_button, *swap, *newb, temp, lb, rb, mb;
  1583.     int btn[] = { 1, 4, 2, 8 };
  1584.  
  1585.     lb = left_button;
  1586.     rb = right_button;
  1587.     mb = middle_button;
  1588.  
  1589.     window_text("Mouse Reconfig\t\n"
  1590.         "      @ Add\n"
  1591.         "      @ Edit\n"
  1592.         "      @ Delete\n"
  1593.         "      @ Mark\n\n", 1);
  1594.  
  1595.     set_window_bars();
  1596.  
  1597. relist:
  1598.     print_button(lb, "Left");
  1599.     print_button(rb, "Right");
  1600.     print_button(mb, "Mid");
  1601.  
  1602.     if ((button = window_check()) < 0)
  1603.     {
  1604.         if (button == -1)
  1605.         {
  1606.             left_button = lb;
  1607.             right_button = rb;
  1608.             middle_button = mb;
  1609.         }
  1610.         return;
  1611.     }
  1612.  
  1613.     print_button(lb, "");
  1614.     print_button(rb, "");
  1615.     print_button(mb, "");
  1616.  
  1617.     new_button = btn[button];
  1618.  
  1619.     if (true_button == 1)
  1620.         newb = &lb;
  1621.     else if (true_button == 2)
  1622.         newb = &rb;
  1623.     else if (true_button == 4)
  1624.         newb = &mb;
  1625.     else goto relist;
  1626.  
  1627.     swap = &new_button;
  1628.     if (lb == new_button)
  1629.         swap = &lb;
  1630.     if (rb == new_button)
  1631.         swap = &rb;
  1632.     if (mb == new_button)
  1633.         swap = &mb;
  1634.  
  1635.     temp = *swap;
  1636.     *swap = *newb;
  1637.     *newb = temp;
  1638.     goto relist;
  1639. }
  1640.  
  1641. void print_button(int button, char *name)
  1642. {
  1643.     int y=0;
  1644.  
  1645.     if (button & 0x1)
  1646.         y = 24;
  1647.     if (button & 0x2)
  1648.         y = 44;
  1649.     if (button & 0x4)
  1650.         y = 34;
  1651.     if (button & 0x8)
  1652.         y = 54;
  1653.  
  1654.     erase_text(win.left + 4, win.top + y, 5);
  1655.     outtextxy(win.left + 4, win.top + y, name);
  1656.     return;
  1657. }
  1658.  
  1659. void adjust_limit(int x, int y, int *xmin, int *ymin, int *xmax, int *ymax)
  1660. {
  1661.     if (x < *xmin)
  1662.         *xmin = x;
  1663.     if (x > *xmax)
  1664.         *xmax = x;
  1665.     if (y < *ymin)
  1666.         *ymin = y;
  1667.     if (y > *ymax)
  1668.         *ymax = y;
  1669.     return;
  1670. }
  1671.  
  1672. int rand_color(void)
  1673. {
  1674.     int color;
  1675.  
  1676.     color_num++;
  1677.     if (flash_mode)
  1678.         switch (color_num %= 6)
  1679.         {
  1680.             case 0:
  1681.                 color = 160;
  1682.                 break;
  1683.             case 1:
  1684.             case 5:
  1685.                 color = 158;
  1686.                 break;
  1687.             case 2:
  1688.             case 4:
  1689.                 color = 156;
  1690.                 break;
  1691.             case 3:
  1692.                 color = 154;
  1693.         }
  1694.     else
  1695.         switch (color_num &= 3)
  1696.         {
  1697.             case 0:
  1698.                 color = 255;
  1699.                 break;
  1700.             case 1:
  1701.                 color = 96;
  1702.                 break;
  1703.             case 2:
  1704.                 color = 80;
  1705.                 break;
  1706.             case 3:
  1707.                 color = 32;
  1708.         }
  1709.     setcolor(color);
  1710.     return color;
  1711. }
  1712.  
  1713. int stagger_color(void)
  1714. {
  1715.     int color;
  1716.  
  1717.     if (flash_mode)
  1718.         switch (color_num)
  1719.         {
  1720.             case 3:
  1721.                 color = 160;
  1722.                 break;
  1723.             case 2:
  1724.             case 4:
  1725.                 color = 158;
  1726.                 break;
  1727.             case 1:
  1728.             case 5:
  1729.                 color = 156;
  1730.                 break;
  1731.             case 0:
  1732.                 color = 154;
  1733.         }
  1734.     else
  1735.         switch (color_num)
  1736.         {
  1737.             case 3:
  1738.                 color = 255;
  1739.                 break;
  1740.             case 2:
  1741.                 color = 96;
  1742.                 break;
  1743.             case 1:
  1744.                 color = 80;
  1745.                 break;
  1746.             case 0:
  1747.                 color = 32;
  1748.         }
  1749.     setcolor(color);
  1750.     return color;
  1751. }
  1752.  
  1753. int wall_color(int num) /* return wall color for linedef <num> */
  1754. {
  1755.     int color, count, type, sec1, sec2;
  1756.  
  1757.     if (!color_scheme)
  1758.     {
  1759.         color = 253;
  1760.         count = 0;
  1761.         if (linedefs[num].sd1 != -1)
  1762.             count++;
  1763.         if (linedefs[num].sd2 != -1)
  1764.             count++;
  1765.         if (count == 1)
  1766.             color = 254;
  1767.  
  1768.         if (linedefs[num].attrib & 1)
  1769.             color = 255;
  1770.         if (type = linedefs[num].type)
  1771.             color = linedefs[num].type % 125 + 1;
  1772.         if (type == 26 || type == 32) /* blue door */
  1773.             color = 32;
  1774.         if (type == 27 || type == 33) /* yellow door */
  1775.             color = 80;
  1776.         if (type == 28 || type == 34) /* red door */
  1777.             color = 96;
  1778.         if (color == 253 && count == 2)
  1779.         {
  1780.             sec1 = sidedefs[linedefs[num].sd1].sector;
  1781.             sec2 = sidedefs[linedefs[num].sd2].sector;
  1782.             if (sectors[sec1].floor != sectors[sec2].floor)
  1783.                 color = 191;
  1784.             if (sectors[sec1].ceiling != sectors[sec2].ceiling)
  1785.                 color = 83;
  1786.         }
  1787.         if (!count)
  1788.             color = 120;
  1789.  
  1790.     } else if (color_scheme == 1) {
  1791.  
  1792.     } else if (color_scheme == 2) {
  1793.         if (linedefs[num].sd1 == -1 || linedefs[num].sd2 == -1)
  1794.             color = 83;
  1795.         else {
  1796.             count = abs(sectors[sidedefs[linedefs[num].sd1].sector].floor -
  1797.                 sectors[sidedefs[linedefs[num].sd2].sector].floor);
  1798.             if (count < 25)
  1799.                 color = 252;
  1800.             else if (count < 65)
  1801.                 color = 253;
  1802.             else if (count < 257)
  1803.                 color = 254;
  1804.             else color = 255;
  1805.         }
  1806.     }
  1807.  
  1808.     setcolor(color);
  1809.     return color;
  1810. }
  1811.  
  1812. void draw_map(void)
  1813. {
  1814.     char msg[30];
  1815.     int i, num, x, y, min, max, bits, pmaxx, pmaxy;
  1816.  
  1817.     int gridsize[] = { 0xfff0, 0xffe0, 0xffc0, 0xff80, 0xff00, 0xfe00 };
  1818.  
  1819.     for (i=0; i<max_vertex; i++)
  1820.     {
  1821.         adjvx[i] = adjustx(vertexes[i].x);
  1822.         adjvy[i] = adjusty(vertexes[i].y);
  1823.     }
  1824.  
  1825.     cleardevice();
  1826.  
  1827.     if (grid)
  1828.     {
  1829.         setcolor(grid);
  1830.         if (testmode) /* draw blockmap blocks in this case */
  1831.         {
  1832.             if ((min = adjusty(blockmap->yorigin + blockmap->ysize * 128)) < 0)
  1833.                 min = 0;
  1834.             if ((max = adjusty(blockmap->yorigin)) > maxy)
  1835.                 max = maxy;
  1836.             for (x=0; x<=blockmap->xsize; x++)
  1837.             {
  1838.                 i = adjustx(blockmap->xorigin + x * 128);
  1839.                 line(i, min, i, max);
  1840.             }
  1841.             if ((min = adjustx(blockmap->xorigin)) < 0)
  1842.                 min = 0;
  1843.             if ((max = adjustx(blockmap->xorigin + blockmap->xsize*128)) > maxx)
  1844.                 max = maxx;
  1845.             for (y=0; y<=blockmap->ysize; y++)
  1846.             {
  1847.                 i = adjusty(blockmap->yorigin + y * 128);
  1848.                 line(min, i, max, i);
  1849.             }
  1850.         } else if (roundoff) {
  1851.             i = 1;
  1852.             while ((num = ((powers[roundoff] * i / scalers[scale]) << 1)) < 8)
  1853.                 i *= 2;
  1854.  
  1855.             x = xoffset - ((midx * scalers[scale]) >> 1) & xor_powers[roundoff];
  1856.             x = adjustx(x);
  1857.             while (x <= maxx)
  1858.             {
  1859.                 line(x, 0, x, maxy);
  1860.                 x += num;
  1861.             }
  1862.  
  1863.             y = yoffset + ((midy * scalers[scale]) >> 1) & xor_powers[roundoff];
  1864.             y = adjusty(y);
  1865.             while (y <= maxy)
  1866.             {
  1867.                 line(0, y, maxx, y);
  1868.                 y += num;
  1869.             }
  1870.         }
  1871.     }
  1872.  
  1873.     if (points)
  1874.     {
  1875.         pmaxx = maxx - points * 2;
  1876.         pmaxy = maxy - points * 2;
  1877.         for (i=0; i<max_vertex; i++)
  1878.             draw_point(adjvx[i], adjvy[i], pmaxx, pmaxy);
  1879.     }
  1880.  
  1881.     free_mem(lthing_num, "lthing_num");
  1882.     free_mem(lthingx, "lthingx");
  1883.     free_mem(lthingy, "lthingy");
  1884.     free_mem(lthing_offsets, "lthing_offsets");
  1885.     lthing_count = 0;
  1886.  
  1887.     if (t_size && things_on)
  1888.     {
  1889.         char *bitfield, *buffer;
  1890.         char bitmask[] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
  1891.         int count=0, size;
  1892.  
  1893.         size = (t_size + 7) >> 3;
  1894.         bitfield = get_mem(size, "bitfield");
  1895.         for (i=0; i<size; i++)
  1896.             bitfield[i] = 0;
  1897.  
  1898.         for (i=0; i<t_size; i++)
  1899.         {
  1900.             bits = things[i].flags;
  1901.             if ((bits & flags_mask) &&
  1902.                 ((bits & flags_mask2) == (flags_mask & flags_mask2)))
  1903.             {
  1904.                 bitfield[i >> 3] |= bitmask[i & 7];
  1905.                 count++;
  1906.             }
  1907.         }
  1908.  
  1909.         count++; /* space for one added thing */
  1910.         count *= 2; /* make it reflect # of bytes instead of # of ints */
  1911.         lthing_num = get_mem(count, "lthing_num");
  1912.         lthingx = get_mem(count, "lthingx");
  1913.         lthingy = get_mem(count, "lthingy");
  1914.         lthing_offsets = get_mem(count, "lthing_offsets");
  1915.  
  1916.         if (count != 1)
  1917.         {
  1918.             buffer = get_mem(4096, "thing image buffer");
  1919.             setcolor(254);
  1920.             for (i=0; i<t_size; i++)
  1921.             {
  1922.                 if (bitfield[i >> 3] & bitmask[i & 7])
  1923.                 {
  1924.                     lthing_num[lthing_count] = i;
  1925.                     if ((num = draw_thing(x = adjustx(things[i].x),
  1926.                         y = adjusty(things[i].y), things[i].type,
  1927.                         things[i].angle, buffer)) != -1)
  1928.                     {
  1929.                         lthingx[lthing_count] = x;
  1930.                         lthingy[lthing_count] = y;
  1931.                         lthing_offsets[lthing_count++] = num;
  1932.                     }
  1933.                 }
  1934.             }
  1935.             free_mem(buffer, "thing image buffer");
  1936.         }
  1937.         free_mem(bitfield, "bitfield");
  1938.  
  1939.     } else {
  1940.         lthing_num = get_mem(2, "lthing_num");
  1941.         lthingx = get_mem(2, "lthingx");
  1942.         lthingy = get_mem(2, "lthingy");
  1943.         lthing_offsets = get_mem(2, "lthing_offsets");
  1944.     }
  1945.  
  1946.     ll_size = 0;
  1947.     setlinestyle(SOLID_LINE, 0, line_size);
  1948.     for (i=0; i<l_size; i++)
  1949.         if (line_visible(i))
  1950.         {
  1951.             llines[ll_size++] = i;
  1952.             wall_color(i);
  1953.             line(win.left, win.top, win.right, win.bottom);
  1954.         }
  1955.  
  1956.     strcpy(msg, "Mode: ");
  1957.     switch (edit_mode)
  1958.     {
  1959.         case 0:
  1960.         case 1:
  1961.             strcat(msg, "Thing");
  1962.             break;
  1963.         case 2:
  1964.         case 3:
  1965.             strcat(msg, "Vertex edit");
  1966.             break;
  1967.         case 4:
  1968.         case 5:
  1969.         case 6:
  1970.             strcat(msg, "Line edit");
  1971.             break;
  1972.         case 7:
  1973.             strcat(msg, "Sector edit");
  1974.             break;
  1975.         case 8:
  1976.             strcat(msg, "Sector blend/copy");
  1977.         default:
  1978.             *msg = 0;
  1979.     }
  1980.     text_color = 254;
  1981.     if (*msg)
  1982.     {
  1983.         text(0, -11, msg);
  1984.     }
  1985.  
  1986.     if (editing_pwad)
  1987.     {
  1988.         sprintf(msg, "Pwad: %s", pwad);
  1989.         i = 0;
  1990.         while (msg[i] != '.') /* strip off the extention */
  1991.             i++;
  1992.         msg[i] = 0;
  1993.         text(-1, -11, msg);
  1994.     }
  1995.     text_color = 255;
  1996.  
  1997.     setcolor(255);
  1998.     sprintf(msg, "Map: E%dM%d", episode, mission);
  1999.     text(-1, -1, msg);
  2000.     print_roundoff();
  2001.     mouse = cur_box_color = old_mark_color = 0;
  2002.     return;
  2003. }
  2004.  
  2005. void print_roundoff(void)
  2006. {
  2007.     char msg[15];
  2008.     int i;
  2009.  
  2010.     i = 1;
  2011.     if (roundoff)
  2012.         i = powers[roundoff];
  2013.     sprintf(msg, "Roundoff: %-2d", i);
  2014.     text(maxx / 3 - 48, -1, msg);
  2015.     return;
  2016. }
  2017.  
  2018. void draw_line(int number, int style) /* draw linedef <number> */
  2019. {
  2020.     struct linesettingstype lineinfo;
  2021.  
  2022.     if (line_visible(number))
  2023.     {
  2024.         getlinesettings(&lineinfo);
  2025.         setlinestyle(style, 0, line_size);
  2026.         line(win.left, win.top, win.right, win.bottom);
  2027.         setlinestyle(lineinfo.linestyle, 0, lineinfo.thickness);
  2028.     }
  2029.     return;
  2030. }
  2031.  
  2032. void draw_line2(int x1, int y1, int x2, int y2)
  2033. {
  2034.     if (line_in_rect(x1, y1, x2, y2, 0, 0, maxx, maxy))
  2035.         line(win.left, win.top, win.right, win.bottom);
  2036.     return;
  2037. }
  2038.  
  2039. void draw_box(int xx1, int yy1, int xx2, int yy2)
  2040. {
  2041.     int x1, y1, x2, y2;
  2042.  
  2043.     x1 = adjustx(xx1);
  2044.     x2 = adjustx(xx2);
  2045.     y1 = adjusty(yy1);
  2046.     y2 = adjusty(yy2);
  2047.  
  2048.     draw_line2(x1, y1, x2, y1);
  2049.     draw_line2(x1, y1, x1, y2);
  2050.     draw_line2(x1, y2, x2, y2);
  2051.     draw_line2(x2, y1, x2, y2);
  2052.     return;
  2053. }
  2054.  
  2055. void draw_point(int xpos, int ypos, int pmaxx, int pmaxy)
  2056. {
  2057.     if (xpos < point_size ||
  2058.          ypos < point_size ||
  2059.          xpos > pmaxx ||
  2060.          ypos > pmaxy) return;
  2061.  
  2062.     putimage(xpos-point_size, ypos-point_size, point_ptr[point_size-1], 3);
  2063.     return;
  2064. }
  2065.  
  2066. int draw_thing(int xpos, int ypos, int type, int angle, char *buffer)
  2067. {
  2068.     char far *shape, *ptr1, far *ptr2;
  2069.     int i, end, shape_no, x, y, z;
  2070.     int xsize, ysize; /* size of shape */
  2071.     int xhalf, yhalf; /* size of half the shape */
  2072.  
  2073.     shape_no = 0;
  2074.     for (i=0; i<thing_max; i++)
  2075.     {
  2076.         if (thing_types[i] == type)
  2077.         {
  2078.             shape_no = thing_shapes[i];
  2079.             break;
  2080.         }
  2081.     }
  2082.  
  2083.     if (things_on == -1)
  2084.     {
  2085.         z = (thing_rad[i] / scalers[scale]) << 1;
  2086.         if (xpos < z || ypos < z || xpos+z > maxx || ypos+z > maxy)
  2087.             return -1;
  2088.  
  2089.         circle(xpos, ypos, z);
  2090.         return z;
  2091.     }
  2092.  
  2093.     if (shape_no > 9 && shape_no < 170) /* monster shape */
  2094.         shape_no += (angle + 22) / 45 * 2 % 16; /* angle pictures */
  2095.  
  2096.     if (things_on == 2) /* small icons */
  2097.         shape_no++;
  2098.  
  2099.     if (shape_no >= no_shapes)
  2100.         fatal_error("shape # out of bounds");
  2101.  
  2102.     shape = shapes + shp_offsets[shape_no]; /* point to the shape */
  2103.     xsize = *shape;
  2104.     ysize = *(shape+2);
  2105.     xhalf = xsize / 2;
  2106.     yhalf = ysize / 2;
  2107.     xpos -= xhalf;
  2108.     ypos -= yhalf;
  2109.  
  2110.     if (xpos < 0 ||
  2111.          ypos < 0 ||
  2112.          xpos+xsize > maxx ||
  2113.          ypos+ysize > maxy) return -1; /* off screen, don't draw */
  2114.  
  2115.     getimage(xpos, ypos, xpos+xsize, ypos+ysize, buffer);
  2116.     ptr1 = buffer+4;
  2117.     ptr2 = shape+4;
  2118.     end = (xsize + 1) * (ysize + 1);
  2119.  
  2120.     for (i=0; i<end; i++)
  2121.     {
  2122.         if (z = *ptr2++)
  2123.             *ptr1++ = z;
  2124.         else
  2125.             ptr1++;
  2126.     }
  2127.     putimage(xpos, ypos, buffer, 0);
  2128.     return shp_offsets[shape_no];
  2129. }
  2130.  
  2131. void center_map(void) /* center the map on the screen */
  2132. {
  2133.     int i, xmax=0, ymax=0, xmin=0, ymin=0, xx, yy;
  2134.  
  2135.     if (v_size)
  2136.     {
  2137.         xmax = xmin = vertexes[0].x;
  2138.         ymax = ymin = vertexes[0].y;
  2139.         for (i=1; i<v_size; i++)
  2140.         {
  2141.             xx = vertexes[i].x;
  2142.             yy = vertexes[i].y;
  2143.             if (xx > xmax) xmax = xx;
  2144.             if (xx < xmin) xmin = xx;
  2145.             if (yy > ymax) ymax = yy;
  2146.             if (yy < ymin) ymin = yy;
  2147.         }
  2148.     }
  2149.     xoffset = (xmin + xmax) / 2;
  2150.     yoffset = (ymin + ymax) / 2;
  2151.  
  2152.     max_vertex = 0;
  2153.     for (i=0; i<l_size; i++)
  2154.     {
  2155.         xx = linedefs[i].v1;
  2156.         if (xx >= max_vertex && xx < v_size)
  2157.             max_vertex = xx + 1;
  2158.         xx = linedefs[i].v2;
  2159.         if (xx >= max_vertex && xx < v_size)
  2160.             max_vertex = xx + 1;
  2161.     }
  2162.     return;
  2163. }
  2164.  
  2165. void text(int xx, int yy, char *msg)
  2166. {
  2167.     int x1, y1, x2, y2;
  2168.  
  2169.     if (xx < 0)
  2170.         xx += maxx - textwidth(msg) + 1;
  2171.     if (yy < 0)
  2172.         yy += maxy - textheight(msg) + 1;
  2173.     x1 = 1;
  2174.     y1 = 1;
  2175.     x2 = xx + textwidth(msg);
  2176.     y2 = yy + textheight(msg);
  2177.  
  2178.     if (xx == 0)
  2179.         x1 = 0;
  2180.     if (yy == 0)
  2181.         y1 = 0;
  2182.     if (x2 > maxx)
  2183.         x2 = maxx;
  2184.     if (y2 > maxy)
  2185.         y2 = maxy;
  2186.  
  2187.     setviewport(xx - x1, yy - y1, x2, y2, 1);
  2188.     clearviewport();
  2189.     setcolor(text_color);
  2190.     outtextxy(x1, y1, msg);
  2191.     setviewport(0, 0, maxx, maxy, 1);
  2192.     return;
  2193. }
  2194.  
  2195. void toptext(char *msg)
  2196. {
  2197.     int m;
  2198.  
  2199.     if (m = mouse)
  2200.         mouse_off();
  2201.     setviewport(0, 0, maxx, textheight(msg)+1, 1);
  2202.     clearviewport();
  2203.     setcolor(255);
  2204.     outtextxy(1, 1, msg);
  2205.     setviewport(0, 0, maxx, maxy, 1);
  2206.     if (mouse)
  2207.         mouse_on();
  2208.     return;
  2209. }
  2210.  
  2211. void toptext2(char *msg, char *msg2)
  2212. {
  2213.     setviewport(0, 0, maxx, textheight(msg)+textheight(msg2)+2, 1);
  2214.     clearviewport();
  2215.     setcolor(255);
  2216.     outtextxy(1, 1, msg);
  2217.     setcolor(128);
  2218.     outtextxy(1, textheight(msg)+2, msg2);
  2219.     setviewport(0, 0, maxx, maxy, 1);
  2220.     return;
  2221. }
  2222.  
  2223. void window_text1(char far *msg, int center, int xplus, int yplus)
  2224. {
  2225.     int i, len, lines, max_len;
  2226.  
  2227.     if (!graph_on) /* if graphics not on yet, ignore messages */
  2228.         return;
  2229.  
  2230.     max_len = 0; /* setup */
  2231.     lines = 0;
  2232.  
  2233.     for (i=0, len=0; i<strlen(msg); i++) /* calc texts dimensions */
  2234.     {
  2235.         if (msg[i] == '\t' || msg[i] == '\n')
  2236.         {
  2237.             if (len > max_len)
  2238.                 max_len = len;
  2239.             len = 0;
  2240.             lines++;
  2241.             continue;
  2242.         }
  2243.         len++;
  2244.     }
  2245.  
  2246.     set_window1(max_len * 8 + xplus, lines * 10 + yplus, center);
  2247.     text_to_window(0, 0, msg, max_len);
  2248.     return;
  2249. }
  2250.  
  2251. void window_text(char far *msg, int center)
  2252. {
  2253.     if (!graph_on) /* if graphics not on yet, ignore messages */
  2254.         return;
  2255.  
  2256.     window_text1(msg, center, 0, 0);
  2257.     draw_buttons();
  2258.     return;
  2259. }
  2260.  
  2261. void text_to_window(int column, int row, char huge *msg, int max_len)
  2262. {
  2263.     char textline[81];
  2264.     int i, index, len, xoffset;
  2265.     int last_num, last_bigb, half_space;
  2266.  
  2267.     index = 0;
  2268.     while (msg[index])
  2269.     {
  2270.         len = 0;
  2271.         last_num = b.num;
  2272.         last_bigb = bigb.num;
  2273.         half_space = 0;
  2274.         while (msg[index] != '\t' && msg[index] != '\n')
  2275.         {
  2276.             if (msg[index] == '@')
  2277.             {
  2278.                 b.pos[b.num].x = win.left + 7 + len*8;
  2279.                 b.pos[b.num].y = win.top + row*10 + 7;
  2280.                 b.pos[b.num].on = 0;
  2281.                 b.num++;
  2282.                 textline[len++] = ' ';
  2283.                 index++;
  2284.                 continue;
  2285.             }
  2286.  
  2287.             if (msg[index] == '|')
  2288.             {
  2289.                 half_space = 1;
  2290.                 index++;
  2291.                 continue;
  2292.             }
  2293.  
  2294.             if (msg[index] == '^')
  2295.             {
  2296.                 setcolor(128);
  2297.                 index++;
  2298.                 continue;
  2299.             }
  2300.  
  2301.             if (msg[index] == '[')
  2302.             {
  2303.                 bigb.pos[bigb.num].x1 = win.left + len*8 + 6;
  2304.                 index++;
  2305.                 continue;
  2306.             }
  2307.  
  2308.             if (msg[index] == ']')
  2309.             {
  2310.                 bigb.pos[bigb.num].x2 = win.left + len*8;
  2311.                 bigb.pos[bigb.num++].y = win.top + row*10 + 7;
  2312.                 index++;
  2313.                 continue;
  2314.             }
  2315.             textline[len++] = msg[index++];
  2316.         }
  2317.         textline[len] = 0;
  2318.         xoffset = column * 8 + half_space * 4;
  2319.         if (msg[index] == '\t')
  2320.             xoffset += (max_len - len) * 4;
  2321.         for (i=last_num; i<b.num; i++)
  2322.             b.pos[i].x += xoffset;
  2323.         outtextxy(xoffset + 4, row*10 + 4, textline);
  2324.         setcolor(255);
  2325.         for (i=last_bigb; i<bigb.num; i++)
  2326.         {
  2327.             bigb.pos[i].x1 += xoffset; /* centering compensation */
  2328.             bigb.pos[i].x2 += xoffset;
  2329.         }
  2330.         row++;
  2331.         index++;
  2332.     }
  2333.     return;
  2334. }
  2335.  
  2336. void draw_buttons(void)
  2337. {
  2338.     int i, x1, x2, y;
  2339.  
  2340.     setviewport(0, 0, maxx, maxy, 1);
  2341.     for (i=0; i<b.num; i++)
  2342.     {
  2343.         setcolor(255);
  2344.         if (b.pos[i].status)
  2345.             setcolor(128);
  2346.         circle(b.pos[i].x, b.pos[i].y, 4);
  2347.     }
  2348.  
  2349.     setcolor(255);
  2350.     for (i=0; i<bigb.num; i++)
  2351.     {
  2352.         x1 = bigb.pos[i].x1;
  2353.         x2 = bigb.pos[i].x2;
  2354.         y = bigb.pos[i].y;
  2355.  
  2356.         line(x1 - 4, y - 6, x2 + 4, y - 6);
  2357.         line(x1 - 4, y + 6, x2 + 4, y + 6);
  2358.         line(x1 - 6, y - 4, x1 - 6, y + 4);
  2359.         line(x1 - 5, y - 4, x1 - 5, y + 4);
  2360.         line(x2 + 5, y - 4, x2 + 5, y + 4);
  2361.         line(x2 + 6, y - 4, x2 + 6, y + 4);
  2362.         line(x1 - 5, y - 5, x1 - 4, y - 5);
  2363.         line(x2 + 4, y - 5, x2 + 5, y - 5);
  2364.         line(x1 - 5, y + 5, x1 - 4, y + 5);
  2365.         line(x2 + 4, y + 5, x2 + 5, y + 5);
  2366.     }
  2367.     return;
  2368. }
  2369.  
  2370. void set_window(int columns, int rows, int center)
  2371. {
  2372.     set_window1(columns*8, rows*10, center);
  2373.     return;
  2374. }
  2375.  
  2376. void set_window1(int xsize, int ysize, int center)
  2377. {
  2378.     int x1, x2, y1, y2;
  2379.  
  2380.     b.num = bigb.num = win.bars = 0;
  2381.  
  2382.     y1 = midy - ysize/2 - 2;
  2383.     y2 = y1 + ysize + 4;
  2384.     switch (center)
  2385.     {
  2386.         case 1:
  2387.             x1 = midx - xsize/2 - 4;
  2388.             x2 = x1 + xsize + 5;
  2389.             break;
  2390.  
  2391.         case 0:
  2392.             x2 = maxx-4;
  2393.             x1 = x2 - xsize - 5;
  2394.             break;
  2395.  
  2396.         case 2:
  2397.             x1 = midx/2 - xsize/2 - 4;
  2398.             x2 = x1 + xsize + 5;
  2399.     }
  2400.  
  2401.     if (x1 < 4)
  2402.         x1 = 4;
  2403.     if (y1 < 4)
  2404.         y1 = 4;
  2405.     if (x2 > maxx-4)
  2406.         x2 = maxx-4;
  2407.     if (y2 > maxy-4)
  2408.         y2 = maxy-4;
  2409.     win.left = x1;
  2410.     win.right = x2;
  2411.     win.top = y1;
  2412.     win.bottom = y2;
  2413.  
  2414.     setcolor(80);
  2415.     line(x1-4, y1-4, x2+4, y1-4);
  2416.     line(x1-4, y1-4, x1-4, y2+4);
  2417.     line(x1-3, y1-3, x2+3, y1-3);
  2418.     line(x1-3, y1-3, x1-3, y2+3);
  2419.     setcolor(82);
  2420.     line(x1-2, y1-2, x2+2, y1-2);
  2421.     line(x1-2, y1-2, x1-2, y2+2);
  2422.     line(x2+1, y1, x2+1, y2+1);
  2423.     line(x1, y2+1, x2+1, y2+1);
  2424.     line(x2+2, y1-1, x2+2, y2+2);
  2425.     line(x1-1, y2+2, x2+2, y2+2);
  2426.     setcolor(84);
  2427.     line(x1-1, y1-1, x2+1, y1-1);
  2428.     line(x1-1, y1-1, x1-1, y2+1);
  2429.     line(x2+3, y1-2, x2+3, y2+3);
  2430.     line(x1-2, y2+3, x2+3, y2+3);
  2431.     setcolor(86);
  2432.     line(x2+4, y1-3, x2+4, y2+4);
  2433.     line(x1-3, y2+4, x2+4, y2+4);
  2434.  
  2435.     setviewport(x1, y1, x2, y2, 1);
  2436.     clearviewport();
  2437.     setcolor(255);
  2438.     return;
  2439. }
  2440.  
  2441. void set_window_bars(void)
  2442. {
  2443.     win.okbar = win.left + (win.right  - win.left) / 4 - 24;
  2444.     win.canbar = win.left + (win.right - win.left) * 3 / 4 - 24;
  2445.  
  2446.     putimage(win.okbar, win.bottom-4, shapes+shp_offsets[292], 0);
  2447.     putimage(win.canbar, win.bottom-4, shapes+shp_offsets[293], 0);
  2448.  
  2449.     win.bars = 1;
  2450.     return;
  2451. }
  2452.  
  2453. void set_cancel_bar(void)
  2454. {
  2455.     win.canbar = win.left + (win.right - win.left) * 3 / 4 - 24;
  2456.     putimage(win.canbar, win.bottom-4, shapes+shp_offsets[293], 0);
  2457.     win.bars = 2;
  2458.     return;
  2459. }
  2460.  
  2461. void set_button_statuses(int num)
  2462. {
  2463.     int i;
  2464.  
  2465.     for (i=0; i<30; i++)
  2466.         b.pos[i].status = num;
  2467.     return;
  2468. }
  2469.  
  2470. int window_check(void)
  2471. {
  2472.     int i, color, cross_status;
  2473.  
  2474.     for (i=0; i<b.num; i++)
  2475.     {
  2476.         color = 0;
  2477.         if (b.pos[i].on)
  2478.             color = 254;
  2479.         draw_cursor(b.pos[i].x-2, b.pos[i].y-2, color);
  2480.     }
  2481.     cross_status = cross_on;
  2482.     cross_on = 0;
  2483.     mouse_on();
  2484.     while (mouse_check());
  2485.     while (1)
  2486.     {
  2487.         while (!mouse_check())
  2488.         {
  2489.             if (keypress == 27 || keypress == 13)
  2490.             {
  2491.                 mouse_off();
  2492.                 cross_on = cross_status;
  2493.                 if (keypress == 13)
  2494.                 {
  2495.                     if (win.bars != 1)
  2496.                         return -2;
  2497.                     return -1;
  2498.                 }
  2499.                 return -99;
  2500.             }
  2501.  
  2502.             if (keypress == '\t')
  2503.                 next_button();
  2504.         }
  2505.  
  2506.         if (true_button)
  2507.             button_status = true_button;
  2508.  
  2509.         if (win.bars == 1 &&
  2510.             mousex < win.okbar + 22 &&
  2511.             mousex > win.okbar + 2 &&
  2512.             mousey < win.bottom + 9 &&
  2513.             mousey > win.bottom - 2)
  2514.         {
  2515.             mouse_off();
  2516.             cross_on = cross_status;
  2517.             return -1;
  2518.         }
  2519.  
  2520.         if (win.bars &&
  2521.             mousex < win.canbar + 47 &&
  2522.             mousex > win.canbar + 2 &&
  2523.             mousey < win.bottom + 9 &&
  2524.             mousey > win.bottom - 2)
  2525.         {
  2526.             mouse_off();
  2527.             cross_on = cross_status;
  2528.             return -99;
  2529.         }
  2530.  
  2531.         for (i=0; i<b.num; i++)
  2532.             if ((abs(mousex - b.pos[i].x) + abs(mousey - b.pos[i].y)) < 5)
  2533.                 if (b.pos[i].status != -1)
  2534.                 {
  2535.                     mouse_off();
  2536.                     cross_on = cross_status;
  2537.                     return i;
  2538.                 }
  2539.  
  2540.         for (i=0; i<bigb.num; i++)
  2541.             if (line_dist(bigb.pos[i].x1, bigb.pos[i].y,
  2542.                 bigb.pos[i].x2, bigb.pos[i].y) < 7)
  2543.             {
  2544.                 mouse_off();
  2545.                 cross_on = cross_status;
  2546.                 return -2 - i;
  2547.             }
  2548.     }
  2549. }
  2550.  
  2551. void next_button(void)
  2552. {
  2553.     int i, num, dist, min_dist=999;
  2554.  
  2555.     for (i=0; i<b.num; i++)
  2556.     {
  2557.         dist = abs(mousex - b.pos[i].x) + abs(mousey - b.pos[i].y);
  2558.         if (dist < min_dist && b.pos[i].status != -1)
  2559.         {
  2560.             min_dist = dist;
  2561.             num = i;
  2562.         }
  2563.     }
  2564.  
  2565.     if (min_dist < 5)
  2566.     {
  2567.         num++;
  2568.         goto next;
  2569.     }
  2570.  
  2571.     for (i=0; i<bigb.num; i++)
  2572.     {
  2573.         dist =line_dist(bigb.pos[i].x1, bigb.pos[i].y,
  2574.             bigb.pos[i].x2, bigb.pos[i].y);
  2575.         if (dist < min_dist)
  2576.         {
  2577.             min_dist = dist;
  2578.             num = -2 - i;
  2579.         }
  2580.     }
  2581.  
  2582.     if (min_dist < 7)
  2583.     {
  2584.         num--;
  2585.         goto next;
  2586.     }
  2587.  
  2588.     if (win.bars == 1)
  2589.     {
  2590.         dist = line_dist(win.okbar+4, win.bottom+3, win.okbar+19,
  2591.             win.bottom+3);
  2592.         if (dist < min_dist)
  2593.         {
  2594.             min_dist = dist;
  2595.             num = -1;
  2596.             if (min_dist < 7)
  2597.             {
  2598.                 num = -99;
  2599.                 goto next;
  2600.             }
  2601.         }
  2602.     }
  2603.  
  2604.     if (win.bars)
  2605.     {
  2606.         dist = line_dist(win.canbar+4, win.bottom+3, win.canbar+44,
  2607.             win.bottom+3);
  2608.         if (dist < min_dist)
  2609.         {
  2610.             num = -99;
  2611.             if (dist < 7)
  2612.             {
  2613.                 num = 0;
  2614.                 goto next;
  2615.             }
  2616.         }
  2617.     }
  2618.     goto set;
  2619.  
  2620. next:
  2621.     if (num == b.num)
  2622.         num = -2;
  2623.  
  2624.     if ((-num - 2) == bigb.num)
  2625.         num = -1;
  2626.  
  2627.     if (num == -1 && win.bars != 1)
  2628.         num = -99;
  2629.  
  2630.     if (num == -99 && !win.bars)
  2631.     {
  2632.         num = 0;
  2633.         goto next;
  2634.     }
  2635.  
  2636. set:
  2637.     mouse_off();
  2638.     if (num > -1)
  2639.     {
  2640.         mousex = b.pos[num].x;
  2641.         mousey = b.pos[num].y;
  2642.  
  2643.     } else if (num == -1) {
  2644.         mousex = win.okbar + 12;
  2645.         mousey = win.bottom + 3;
  2646.  
  2647.     } else if (num == -99) {
  2648.         mousex = win.canbar + 24;
  2649.         mousey = win.bottom + 3;
  2650.  
  2651.     } else {
  2652.         num = -num - 2;
  2653.         mousex = (bigb.pos[num].x1 + bigb.pos[num].x2) / 2;
  2654.         mousey = bigb.pos[num].y;
  2655.     }
  2656.     mouse_on();
  2657.     return;
  2658. }
  2659.  
  2660. void await_release(void) /* wait until mouse buttons released */
  2661. {
  2662.     mouse_check();
  2663.     ignore_button = true_button;
  2664.     mouse_off();
  2665.     return;
  2666. }
  2667.  
  2668. void await_release_on(void)
  2669. {
  2670.     mouse_check();
  2671.     ignore_button = true_button;
  2672.     return;
  2673. }
  2674.  
  2675. void draw_cursor(int x, int y, int color)
  2676. {
  2677.     char image[125];
  2678.     int i;
  2679.  
  2680.     for (i=0; i<4; i++)
  2681.         image[i] = point_ptr[1][i];
  2682.     for (i=0; i<121; i++)
  2683.         image[i+4] = point_ptr[1][i+4] & color;
  2684.     putimage(x, y, image, 0);
  2685.     return;
  2686. }
  2687.  
  2688. void fatal_error(char *msg, ...) /* terminate with error */
  2689. {
  2690.     va_list args;
  2691.  
  2692.     if (attempt_save)
  2693.     {
  2694.         fprintf(stderr, "Failed.\n");
  2695.         exit(1);
  2696.     }
  2697.  
  2698.     closegraph();
  2699.     open_prog_file("error.log", "a");
  2700.     va_start(args, msg);
  2701.  
  2702.     fprintf(fp, "--------------------\n");
  2703.     fprintf(stderr, "Fatal error: ");
  2704.     fprintf(fp, "Fatal error: ");
  2705.     vfprintf(stderr, msg, args);
  2706.     vfprintf(fp, msg, args);
  2707.     fprintf(stderr, "\n");
  2708.     fprintf(fp, "\n");
  2709.  
  2710.     va_end(args);
  2711.     attempt_save = 1;
  2712.     fprintf(stderr, "Attempting to save map to 'exit.wad'...");
  2713.     strcpy(pwad, "exit");
  2714.     save_wad_map(0);
  2715.     fprintf(stderr, "successful.\n");
  2716.     exit(1);
  2717. }
  2718.  
  2719. void error(char *errmsg, ...)
  2720. {
  2721.     char msg[4096] = "Error!\t\n";
  2722.     va_list args;
  2723.  
  2724.     if (!graph_on)
  2725.         fatal_error(errmsg);
  2726.  
  2727.     va_start(args, errmsg);
  2728.     vsprintf(msg + 8, errmsg, args);
  2729.     va_end(args);
  2730.  
  2731.     strcat(msg, "\n");
  2732.     window_text(msg, 1);
  2733.     await_release();
  2734.  
  2735.     while (!mouse_check())
  2736.         if (keypress)
  2737.             break;
  2738.  
  2739.     await_release();
  2740.     return;
  2741. }
  2742.  
  2743. void farmem_error(char *msg, ulong size)
  2744. {
  2745.     char errmsg[200];
  2746.  
  2747.     sprintf(errmsg, "Out of far memory\t"
  2748.         "Couldn't allocate space for the %s\t"
  2749.         "Needed %lu bytes and only had %lu", msg, size, farcoreleft());
  2750.     error(errmsg);
  2751.     return;
  2752. }
  2753.  
  2754. void deadend_error(void)
  2755. {
  2756.     error("Line dead-end.  Use error checker on the Sectors.");
  2757. }
  2758.  
  2759. void rd_error(void)
  2760. {
  2761.     fatal_error("Failed on read from WAD file");
  2762. }
  2763.  
  2764. void wr_error(void)
  2765. {
  2766.     fatal_error("Failed on write to WAD file");
  2767. }
  2768.  
  2769. void dir_error(void)
  2770. {
  2771.     fatal_error("WAD file directory structure corrupt");
  2772. }
  2773.  
  2774. void sw2_notice(void)
  2775. {
  2776.     if (!sw_doom)
  2777.         return;
  2778.  
  2779.     error("In compliance with id's requests, this editor 'utility' has\n"
  2780.         "been made to not work with the shareware version of doom.\n"
  2781.         "Your version of doom has been detected as the shareware\n"
  2782.         "version.  Please register doom if you wish to use DMapEdit.\n");
  2783.  
  2784.     fatal_error("Shareware Doom");
  2785. }
  2786.  
  2787. void erase_text(int x, int y, int xsize)
  2788. {
  2789.     setviewport(x, y, x + xsize*8 - 1, y + 7, 1);
  2790.     clearviewport();
  2791.     setviewport(0, 0, maxx, maxy, 1);
  2792.     return;
  2793. }
  2794.  
  2795. int cursored_get(int x, int y)
  2796. {
  2797.     int color, counter;
  2798.  
  2799.     color = 254;
  2800.     counter = 0;
  2801.     while (!kbhit())
  2802.         if (counter++ == 1500)
  2803.         {
  2804.             draw_cursor(x+1, y+1, color);
  2805.             color ^= 254;
  2806.             counter = 0;
  2807.         }
  2808.     draw_cursor(x+1, y+1, 0);
  2809.     return getch();
  2810. }
  2811.  
  2812. int get_number(int x, int y, int old_num, int max, int min)
  2813. {
  2814.     char key[7];
  2815.     int column, row, pos, neg;
  2816.     long value, num;
  2817.  
  2818.     column = win.left + x * 8 + 4;
  2819.     row = win.top + y * 10 + 4;
  2820.     pos = neg = 0;
  2821.     num = strlen(itoa(max, key, 10));
  2822.     if (strlen(itoa(min, key, 10)) > num)
  2823.         num = strlen(key);
  2824.     erase_text(column, row, num);
  2825.     key[1] = num = 0;
  2826.  
  2827.     while ((*key = cursored_get(column, row)) != 13)
  2828.     {
  2829.         if (*key == 8)
  2830.         {
  2831.             if (!pos)
  2832.                 continue;
  2833.             pos--;
  2834.             if (!pos && neg)
  2835.             {
  2836.                 neg = 0;
  2837.                 continue;
  2838.             }
  2839.             num /= 10;
  2840.             column -= 8;
  2841.             erase_text(column, row, 1);
  2842.             continue;
  2843.         }
  2844.         if (*key == '-' && pos == 0 && min < 0)
  2845.             neg = 1;
  2846.         else {
  2847.             if (!isdigit(*key))
  2848.                 continue;
  2849.             if (neg)
  2850.                 value = num * 10 - *key + '0';
  2851.             else
  2852.                 value = num * 10 + *key - '0';
  2853.             if (value > max || value < min)
  2854.                 continue;
  2855.             num = value;
  2856.         }
  2857.         outtextxy(column, row, key);
  2858.         column += 8;
  2859.         pos++;
  2860.     }
  2861.     if (pos == neg)
  2862.     {
  2863.         num = old_num;
  2864.         sprintf(key, "%d", num);
  2865.         text(column - (neg*8), row, key);
  2866.     }
  2867.     return num;
  2868. }
  2869.  
  2870. int getkey(void) /* get normal or extended keypress */
  2871. {
  2872.     int key;
  2873.  
  2874.     if (!(key = getch()))
  2875.         key = getch() + 1000;
  2876.     if (key >= 'A' && key <= 'Z')
  2877.         key += 0x20; /* remap uppercase to lowercase */
  2878.     if (key == 1016 || key == 1045) /* alt-q and alt-x */
  2879.         key = 27; /* escape key */
  2880.     return key;
  2881. }
  2882.  
  2883. /* input 8 characters (for filenames and wad subfilenames) */
  2884.  
  2885. int get8(char *s, char *deflt, int column, int row)
  2886. {
  2887.     char inbuf[256], key[2];
  2888.     int pos;
  2889.  
  2890.     erase_text(column, row, 8);
  2891.     pos = 0;
  2892.     key[1] = 0;
  2893.     while ((*key = cursored_get(column, row)) != 13)
  2894.     {
  2895.         if (*key == 27)
  2896.         {
  2897.             strcpy(s, deflt); /* use default */
  2898.             erase_text(column - pos*8, row, 8);
  2899.             text(column - pos*8, row, s);
  2900.             return 1;
  2901.         }
  2902.  
  2903.         if (*key == 8)
  2904.         {
  2905.             if (!pos)
  2906.                 continue;
  2907.             pos--;
  2908.             column -= 8;
  2909.             erase_text(column, row, 1);
  2910.             continue;
  2911.         }
  2912.  
  2913.         if (!(isdigit(*key) || isalpha(*key) || *key == '_'))
  2914.             continue;
  2915.         if (pos == 8)
  2916.             continue;
  2917.  
  2918.         if (islower(*key))
  2919.             *key -= 32;
  2920.         outtextxy(column, row, key);
  2921.         column += 8;
  2922.         s[pos] = *key;
  2923.         pos++;
  2924.     }
  2925.  
  2926.     if (!pos) /* null string? */
  2927.     {
  2928.         strcpy(s, deflt); /* use default */
  2929.         text(column, row, s);
  2930.         return 0;
  2931.     }
  2932.     while (pos<9)
  2933.         s[pos++] = 0;
  2934.     return 0;
  2935. }
  2936.  
  2937. void fix_wadname(char *name)
  2938. {
  2939.     int i, len;
  2940.  
  2941.     i = strlen(pwad);
  2942.     while (--i)
  2943.         if (pwad[i] == '\\')
  2944.         {
  2945.             i++;
  2946.             break;
  2947.         }
  2948.  
  2949.     len = 0;
  2950.     while (pwad[i] && pwad[i] != '.' && len < 8)
  2951.         name[len++] = pwad[i++];
  2952.     name[len] = 0;
  2953.     return;
  2954. }
  2955.  
  2956. int get_wadname(char *mode1, char *mode2)
  2957. {
  2958.     char inbuf[128], name[9];
  2959.     int i, column, row;
  2960.  
  2961.     fix_wadname(name);
  2962.     sprintf(inbuf, "%s map %s working WAD file\t\n"
  2963.         "Filename (%s):           \n", mode1, mode2, name);
  2964.     window_text(inbuf, 1);
  2965.  
  2966.     column = win.left + strlen(name) * 8 + 108;
  2967.     row = win.top + 24;
  2968.     i = get8(inbuf, name, column, row);
  2969.     if (!i)
  2970.     {
  2971.         editing_pwad = 1;
  2972.         strcpy(pwad, inbuf);
  2973.         strcat(pwad, ".WAD");
  2974.     }
  2975.     return i;
  2976. }
  2977.  
  2978. int file_picklist(char *mask)
  2979. { /*
  2980.     char msg[60], temp[6];
  2981.     int i, list_num, list_size, columns, rows, type;
  2982.     int old_num, new_num;
  2983.  
  2984.     /* work on this */
  2985.  
  2986.     rows = (maxy / 20) * 2 - 1; /* make sure it's an odd number */
  2987.     columns = thing_name_size + 13;
  2988.     list_size = (rows - 6) / 2;
  2989.  
  2990.     list_num = 0;
  2991.     for (i=0; i<thing_max; i++)
  2992.         if (thing_types[i] == num)
  2993.         {
  2994.             list_num = i - list_size / 2;
  2995.             break;
  2996.         }
  2997.  
  2998. re_list:
  2999.     if (list_num < 0)
  3000.         list_num += thing_max; /* wrap around */
  3001.  
  3002.     set_window(columns, rows, 0);
  3003.     text_to_window(0, 0, "Select type:\t\n\n[ More ]\t", columns);
  3004.     text_to_window(0, rows-1, "[ More ]\t", columns);
  3005.     for (i=0; i<list_size; i++)
  3006.     {
  3007.         type = thing_types[list_num];
  3008.         sprintf(msg, "%Fs\n", thing_names[list_num]);
  3009.         text_to_window(6, i*2+5, msg, 0);
  3010.         yy[i] = i * 20 + 57;
  3011.         xx[i] = draw_thing2( (i & 1) * 24 + 14, yy[i], list_num);
  3012.         xx[i] += win.left;
  3013.         yy[i] += win.top;
  3014.         index[i] = list_num++;
  3015.         if (list_num >= thing_max)
  3016.             list_num = 0;
  3017.     }
  3018.     draw_buttons();
  3019.     mouse_on();
  3020.     old_num = -1;
  3021.  
  3022.     while (mouse_check()); /* wait for mouse button release */
  3023.     while (1)
  3024.     {
  3025.         while (!mouse_check() && !keypress)
  3026.         {
  3027.             new_num = -1;
  3028.             for (i=0; i<list_size; i++)
  3029.                 if ((abs(mousex - xx[i]) + abs(mousey - yy[i])) < 16)
  3030.                     new_num = i;
  3031.             if (new_num != old_num)
  3032.             {
  3033.                 if (old_num != -1)
  3034.                 {
  3035.                     image_restore(xx[old_num], yy[old_num]);
  3036.                     setcolor(255);
  3037.                     mouse_off();
  3038.                     reprint_line(index[old_num], old_num, columns-6);
  3039.                     mouse_on();
  3040.                 }
  3041.                 if (new_num != -1)
  3042.                 {
  3043.                     mouse_off();
  3044.                     box_thing(xx[new_num], yy[new_num],
  3045.                         shp_offsets[thing_shapes[index[new_num]]]);
  3046.                     setcolor(254);
  3047.                     reprint_line(index[new_num], new_num, columns-6);
  3048.                     mouse_on();
  3049.                 }
  3050.                 old_num = new_num;
  3051.             }
  3052.         }
  3053.  
  3054.         if (keypress)
  3055.         {
  3056.             if (keypress == 27)
  3057.             {
  3058.                 mouse_off();
  3059.                 return num;
  3060.             }
  3061.  
  3062.             if (keypress == 13 && new_num != -1)
  3063.             {
  3064.                 mouse_off();
  3065.                 return thing_types[index[new_num]];
  3066.             }
  3067.  
  3068.             if (keypress == 1073) /* page up */
  3069.             {
  3070.                 list_num -= list_size * 2;
  3071.                 mouse_off();
  3072.                 goto re_list;
  3073.             }
  3074.  
  3075.             if (keypress == 1081) /* page down */
  3076.             {
  3077.                 mouse_off();
  3078.                 goto re_list;
  3079.             }
  3080.  
  3081.             if (keypress == 1071) /* home */
  3082.             {
  3083.                 list_num = 0;
  3084.                 mouse_off();
  3085.                 goto re_list;
  3086.             }
  3087.             continue; /* end of key checks, below is mouse button pressed */
  3088.         }
  3089.  
  3090.         if (mousex < win.left - 5 ||
  3091.             mousex > win.right + 5 ||
  3092.             mousey < win.top - 5 ||
  3093.             mousey > win.bottom + 5)
  3094.         {
  3095.             mouse_off();
  3096.             return num;
  3097.         }
  3098.  
  3099.         if (line_dist(bigb.pos[0].x1, bigb.pos[0].y,
  3100.             bigb.pos[0].x2, bigb.pos[0].y) < 7)
  3101.         {
  3102.             list_num -= list_size * 2;
  3103.             mouse_off();
  3104.             goto re_list;
  3105.         }
  3106.  
  3107.         if (line_dist(bigb.pos[1].x1, bigb.pos[1].y,
  3108.             bigb.pos[1].x2, bigb.pos[1].y) < 7)
  3109.         {
  3110.             mouse_off();
  3111.             goto re_list;
  3112.         }
  3113.  
  3114.         if (new_num != -1)
  3115.         {
  3116.             mouse_off();
  3117.             return thing_types[index[new_num]];
  3118.         }
  3119.     } */
  3120. }
  3121.  
  3122. void sync_time(void)
  3123. {
  3124.     struct time t;
  3125.  
  3126.     gettime(&t);
  3127.     systime = t.ti_sec * 100 + t.ti_hund;
  3128.     return;
  3129. }
  3130.  
  3131. int wait(int delay) /* attemp to time sync animation */
  3132. {
  3133.     int tm, dif;
  3134.     struct time t;
  3135.  
  3136.     gettime(&t);
  3137.     tm = t.ti_sec * 100 + t.ti_hund;
  3138.     dif = tm - systime;
  3139.     if (dif < 0)
  3140.         dif += 6000; /* wrap-around */
  3141.     if (dif < delay)
  3142.         return 0;
  3143.     systime = tm;
  3144.     return 1;
  3145. }
  3146.  
  3147. void open_prog_file(char *name, char *mode)
  3148. {
  3149.     char fullpath[100];
  3150.  
  3151.     strcpy(fullpath, path);
  3152.     strcat(fullpath, name);
  3153.  
  3154.     if ((fp = fopen(fullpath, mode)) == NULL)
  3155.         fatal_error("Can't open \"%s\"", name);
  3156.     return;
  3157. }
  3158.  
  3159. int read_ini_file(int gmode, char *gname)
  3160. {
  3161.     char str[101], *var, *setting;
  3162.     int line=0, num, *int_ptr;
  3163.  
  3164.     char *variables[] = {
  3165.         "doom path",
  3166.         "edit mode",
  3167.         "zoom",
  3168.         "video driver",
  3169.         "video mode",
  3170.         "episode",
  3171.         "mission",
  3172.         "backup",
  3173.         "grid",
  3174.         "pwad path1",
  3175.         "pwad path2",
  3176.         "pwad path3",
  3177.         "crosshare",
  3178.         "flash mode",
  3179.         "skip intro",
  3180.         "left mouse button",
  3181.         "middle mouse button",
  3182.         "right mouse button",
  3183.         "*end"
  3184.     };
  3185.  
  3186.     if (!(fp = fopen("dmapedit.ini", "r"))) /* check current directory.. */
  3187.     {
  3188.         strcpy(str, path); /* if not there, see if it's in home dir */
  3189.         strcat(str, "dmapedit.ini");
  3190.  
  3191.         if ((fp = fopen(str, "r")) == NULL)
  3192.             return gmode; /* no ini file, so forget about reading it */
  3193.     }
  3194.  
  3195.     while (fgets(str, 100, fp))
  3196.     {
  3197.         line++;
  3198.         if (*str == '\n' || *str == '*')
  3199.             continue; /* skip blank lines and comments */
  3200.  
  3201.         var = strtok(str, "=");
  3202.         if (!var)
  3203.         {
  3204.             fclose(fp);
  3205.             fatal_error("Error in \"dmapedit.ini\", line #%d", var, line);
  3206.         }
  3207.  
  3208.         setting = strtok(NULL, "\n");
  3209.         for (num=0; stricmp(variables[num], "*end"); num++)
  3210.             if (!stricmp(variables[num], var))
  3211.                 break;
  3212.  
  3213.         if (!stricmp(variables[num], "*end"))
  3214.         {
  3215.             fclose(fp);
  3216.             fatal_error("Unknown variable: \"%s\"\n"
  3217.                 "   In \"dmapedit.ini\", line #%d", var, line);
  3218.         }
  3219.  
  3220.         switch (num)
  3221.         {
  3222.             case 0: /* doom path */
  3223.                 strncpy(iwad, setting, 79);
  3224.                 iwad[79] = 0;
  3225.                 break;
  3226.  
  3227.             case 1: /* edit mode */
  3228.                 if (!stricmp(setting, "things"))
  3229.                     edit_mode = 0;
  3230.                 else if (!stricmp(setting, "vertexes"))
  3231.                     edit_mode = 2;
  3232.                 else if (!stricmp(setting, "lines"))
  3233.                     edit_mode = 4;
  3234.                 else if (!stricmp(setting, "sectors"))
  3235.                     edit_mode = 7;
  3236.                 else goto err;
  3237.                 break;
  3238.  
  3239.             case 2: /* zoom */
  3240.                 num = atoi(setting);
  3241.                 if (num < 0 || num > MAX_ZOOM)
  3242.                     goto err;
  3243.                 scale = num;
  3244.                 things_on = scale>2 ? 2 : 1;
  3245.                 break;
  3246.  
  3247.             case 3: /* video driver */
  3248.                 strncpy(gname, setting, 8);
  3249.                 gname[8] = 0;
  3250.                 break;
  3251.  
  3252.             case 4: /* video mode */
  3253.                 gmode = atoi(setting);
  3254.                 break;
  3255.  
  3256.             case 5: /* episode */
  3257.                 num = atoi(setting);
  3258.                 if (num < 1 || num > 3)
  3259.                     goto err;
  3260.                 episode = num;
  3261.                 break;
  3262.  
  3263.             case 6: /* mission */
  3264.                 num = atoi(setting);
  3265.                 if (num < 1 || num > 9)
  3266.                     goto err;
  3267.                 mission = num;
  3268.                 break;
  3269.  
  3270.             case 7: /* backup */
  3271.                 if (!stricmp(setting, "yes"))
  3272.                     backup = 1;
  3273.                 else if (!stricmp(setting, "no"))
  3274.                     backup = 0;
  3275.                 else goto err;
  3276.                 break;
  3277.  
  3278.             case 8: /* grid */
  3279.                 if (!stricmp(setting, "off"))
  3280.                 {
  3281.                     grid = 0;
  3282.                     break;
  3283.                 }
  3284.  
  3285.                 num = atoi(setting);
  3286.                 if (num < 1 || num > 3)
  3287.                     goto err;
  3288.  
  3289.                 grid = num + 251;
  3290.                 break;
  3291.  
  3292.             case 9: /* pwad path1 */
  3293.                 pwad1 = get_mem(strlen(setting) + 1, "pwad path1");
  3294.                 strcpy(pwad1, setting);
  3295.                 break;
  3296.  
  3297.             case 10: /* pwad path2 */
  3298.                 pwad2 = get_mem(strlen(setting) + 1, "pwad path2");
  3299.                 strcpy(pwad2, setting);
  3300.                 break;
  3301.  
  3302.             case 11: /* pwad path3 */
  3303.                 pwad3 = get_mem(strlen(setting) + 1, "pwad path3");
  3304.                 strcpy(pwad3, setting);
  3305.                 break;
  3306.  
  3307.             case 12: /* crosshare */
  3308.                 if (!stricmp(setting, "on"))
  3309.                     cross_on = 1;
  3310.                 else if (!stricmp(setting, "off"))
  3311.                     cross_on = 0;
  3312.                 else goto err;
  3313.                 break;
  3314.  
  3315.             case 13: /* flash mode */
  3316.                 if (!stricmp(setting, "old"))
  3317.                     flash_mode = 0;
  3318.                 else if (!stricmp(setting, "new"))
  3319.                     flash_mode = 1;
  3320.                 else goto err;
  3321.                 break;
  3322.  
  3323.             case 14: /* skip intro */
  3324.                 if (!stricmp(setting, "yes"))
  3325.                     bypass_sw = 1;
  3326.                 else if (!stricmp(setting, "no"))
  3327.                     bypass_sw = 0;
  3328.                 else goto err;
  3329.                 break;
  3330.  
  3331.             case 15: /* left mouse button */
  3332.                 int_ptr = &left_button;
  3333.  
  3334.             case 16: /* middle mouse button */
  3335.                 if (num == 16)
  3336.                     int_ptr = &middle_button;
  3337.  
  3338.             case 17: /* right mouse button */
  3339.                 if (num == 17)
  3340.                     int_ptr = &right_button;
  3341.  
  3342.                 if (!stricmp(setting, "add"))
  3343.                     *int_ptr = 1;
  3344.                 else if (!stricmp(setting, "delete"))
  3345.                     *int_ptr = 2;
  3346.                 else if (!stricmp(setting, "edit"))
  3347.                     *int_ptr = 4;
  3348.                 else if (!stricmp(setting, "mark"))
  3349.                     *int_ptr = 8;
  3350.                 else goto err;
  3351.                 break;
  3352.         }
  3353.     }
  3354.     fclose(fp);
  3355.     return gmode;
  3356.  
  3357. err:
  3358.     fclose(fp);
  3359.     fatal_error("File \"dmapedit.ini\", line #%d\n"
  3360.         "unknown setting: \"%s\"\n"
  3361.         "   for variable: \"%s\"", line, setting, var);
  3362. }
  3363.  
  3364. void init_graphics(int gmode, char *gname)
  3365. {
  3366.     int i, low, high;
  3367.     char name[80], pal[768];
  3368.     int gdriver, errorcode;
  3369.     union REGS regs;
  3370.     struct SREGS segregs;
  3371.  
  3372.     /* initialize graphics and local variables */
  3373.     gdriver = installuserdriver(gname, 0);
  3374.     initgraph(&gdriver, &gmode, path);
  3375.  
  3376.     /* read result of initialization */
  3377.     errorcode = graphresult();
  3378.     if (errorcode != grOk) /* an error occured */
  3379.         fatal_error("Graphics: %s", grapherrormsg(errorcode));
  3380.  
  3381.     graph_on = 1;
  3382.     maxx = getmaxx();
  3383.     maxy = getmaxy();
  3384.     if (maxx < 639 || maxy < 399)
  3385.         fatal_error("Get a real video card!");
  3386.  
  3387.     midx = maxx / 2;
  3388.     midy = maxy / 2;
  3389.     setbkcolor(0);
  3390.     settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
  3391.  
  3392.     strcpy(name, path);
  3393.     strcat(name, "palette.dme");
  3394.     if ((fp = fopen(name, "rb")) == NULL)
  3395.         fatal_error("Can't open file \"palette.dme\"");
  3396.     if (fread(pal, sizeof(pal), 1, fp) != 1)
  3397.         fatal_error("file \"palette.dme\" is corrupt");
  3398.     fclose(fp);
  3399.  
  3400.     regs.h.ah = 0x10;
  3401.     regs.h.al = 0x12;
  3402.     regs.x.bx = 0;
  3403.     regs.x.cx = 256;
  3404.     regs.x.dx = FP_OFF(pal);
  3405.     segregs.es = FP_SEG(pal);
  3406.     int86x(0x10, ®s, ®s, &segregs); /* set the palette */
  3407.     return;
  3408. }
  3409.  
  3410. void init_mouse(void)
  3411. {
  3412.     union REGS regs;
  3413.  
  3414.     regs.x.ax = 0;
  3415.     int86(0x33, ®s, ®s);
  3416.     if (regs.x.ax == 0)
  3417.         fatal_error("Mouse driver not installed (required)");
  3418.  
  3419.     mouse_maxx = maxx - 8;
  3420.     mouse_maxy = maxy - 14;
  3421.     mousex = maxx / 2;
  3422.     mousey = maxy / 2;
  3423.     button_status = 0;
  3424.     return;
  3425. }
  3426.