home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / util / lev_comp.y < prev    next >
Encoding:
Lex Description  |  1993-08-01  |  35.4 KB  |  1,543 lines  |  [TEXT/R*ch]

  1. %{
  2. /*    SCCS Id: @(#)lev_comp.c    3.1    93/05/15    */
  3. /*    Copyright (c) 1989 by Jean-Christophe Collet */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5.  
  6. /*
  7.  * This file contains the Level Compiler code
  8.  * It may handle special mazes & special room-levels
  9.  */
  10.  
  11. /* In case we're using bison in AIX.  This definition must be
  12.  * placed before any other C-language construct in the file
  13.  * excluding comments and preprocessor directives (thanks IBM
  14.  * for this wonderful feature...).
  15.  *
  16.  * Note: some cpps barf on this 'undefined control' (#pragma).
  17.  * Addition of the leading space seems to prevent barfage for now,
  18.  * and AIX will still see the directive in its non-standard locale.
  19.  */
  20.  
  21. #ifdef _AIX
  22.  #pragma alloca        /* keep leading space! */
  23. #endif
  24.  
  25. #include "hack.h"
  26. #include "sp_lev.h"
  27. #ifndef O_WRONLY
  28. # include <fcntl.h>
  29. #endif
  30. #ifndef O_CREAT    /* some older BSD systems do not define O_CREAT in <fcntl.h> */
  31. # include <sys/file.h>
  32. #endif
  33. #ifndef O_BINARY    /* used for micros, no-op for others */
  34. # define O_BINARY 0
  35. #endif
  36.  
  37. #ifdef MICRO
  38. # define OMASK FCMASK
  39. #else
  40. # define OMASK 0644
  41. #endif
  42.  
  43. #define MAX_REGISTERS    10
  44. #define ERR        (-1)
  45.  
  46. #define New(type)        (type *) alloc(sizeof(type))
  47. #define NewTab(type, size)    (type **) alloc(sizeof(type *) * size)
  48.  
  49. #ifdef MICRO
  50. # undef exit
  51. extern void FDECL(exit, (int));
  52. #endif
  53.  
  54. extern void FDECL(yyerror, (const char *));
  55. extern void FDECL(yywarning, (const char *));
  56. extern int NDECL(yylex);
  57. int NDECL(yyparse);
  58.  
  59. extern char *FDECL(dup_string,(char *));
  60. extern int FDECL(get_floor_type, (CHAR_P));
  61. extern int FDECL(get_room_type, (char *));
  62. extern int FDECL(get_trap_type, (char *));
  63. extern int FDECL(get_monster_id, (char *, CHAR_P));
  64. extern int FDECL(get_object_id, (char *));
  65. extern boolean FDECL(check_monster_char, (CHAR_P));
  66. extern boolean FDECL(check_object_char, (CHAR_P));
  67. extern char FDECL(what_map_char, (CHAR_P));
  68. extern void FDECL(scan_map, (char *));
  69. extern void NDECL(wallify_map);
  70. extern boolean NDECL(check_subrooms);
  71. extern void FDECL(check_coord, (int, int, const char *));
  72. extern void NDECL(store_part);
  73. extern void NDECL(store_room);
  74. extern void FDECL(write_maze, (int, specialmaze *));
  75. extern void FDECL(write_lev, (int, splev *));
  76. extern void FDECL(free_rooms, (room **, int));
  77.  
  78. static struct reg {
  79.     int x1, y1;
  80.     int x2, y2;
  81. }        current_region;
  82.  
  83. static struct coord {
  84.     int x;
  85.     int y;
  86. }        current_coord, current_align;
  87.  
  88. static struct size {
  89.     int height;
  90.     int width;
  91. }        current_size;
  92.  
  93. char tmpmessage[256];
  94. altar *tmpaltar[256];
  95. lad *tmplad[256];
  96. stair *tmpstair[256];
  97. digpos *tmpdig[256];
  98. digpos *tmppass[32];
  99. char *tmpmap[ROWNO];
  100. region *tmpreg[256];
  101. lev_region *tmplreg[32];
  102. door *tmpdoor[256];
  103. room_door *tmprdoor[256];
  104. trap *tmptrap[256];
  105. monster *tmpmonst[256];
  106. object *tmpobj[256];
  107. drawbridge *tmpdb[256];
  108. walk *tmpwalk[256];
  109. gold *tmpgold[256];
  110. fountain *tmpfountain[256];
  111. sink *tmpsink[256];
  112. pool *tmppool[256];
  113. engraving *tmpengraving[256];
  114. mazepart *tmppart[10];
  115. room *tmproom[MAXNROFROOMS*2];
  116. corridor *tmpcor[256];
  117.  
  118. static specialmaze maze;
  119. static splev special_lev;
  120. static lev_init init_lev;
  121.  
  122. static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS];
  123. static struct coord plist[MAX_REGISTERS];
  124.  
  125. int n_olist = 0, n_mlist = 0, n_plist = 0;
  126.  
  127. unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0;
  128. unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0;
  129. unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0;
  130. unsigned int nfountain = 0, npool = 0, nsink = 0, npass = 0;
  131.  
  132. static unsigned long lev_flags = 0;
  133.  
  134. unsigned int max_x_map, max_y_map;
  135.  
  136. static xchar in_room;
  137.  
  138. extern int fatal_error;
  139. extern int want_warnings;
  140. extern const char *fname;
  141.  
  142. %}
  143.  
  144. %union
  145. {
  146.     int    i;
  147.     char*    map;
  148.     struct {
  149.         xchar room;
  150.         xchar wall;
  151.         xchar door;
  152.     } corpos;
  153. }
  154.  
  155.  
  156. %token    <i> CHAR INTEGER BOOLEAN
  157. %token    <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
  158. %token    <i> OBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
  159. %token    <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING
  160. %token    <i> RANDOM_OBJECTS_ID RANDOM_MONSTERS_ID RANDOM_PLACES_ID
  161. %token    <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID
  162. %token    <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV CHANCE_ID
  163. %token    <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
  164. %token    <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
  165. %token    <i> DIRECTION RANDOM_TYPE O_REGISTER M_REGISTER P_REGISTER A_REGISTER
  166. %token    <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
  167. %token    <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
  168. %token    <i> MON_APPEARANCE
  169. %token    <i> ',' ':' '(' ')' '[' ']'
  170. %token    <map> STRING MAP_ID
  171. %type    <i> h_justif v_justif trap_name room_type door_state light_state
  172. %type    <i> alignment altar_type a_register roomfill filling door_pos
  173. %type    <i> door_wall walled secret curse_state enchantment amount
  174. %type    <i> engraving_type flags flag_list prefilled lev_region lev_init
  175. %type    <i> monster monster_c m_register object object_c o_register
  176. %type    <map> string maze_def level_def m_name o_name art_name
  177. %type    <corpos> corr_spec
  178. %start    file
  179.  
  180. %%
  181. file        : /* nothing */
  182.         | levels
  183.         ;
  184.  
  185. levels        : level
  186.         | level levels
  187.         ;
  188.  
  189. level        : maze_level
  190.         | room_level
  191.         ;
  192.  
  193. maze_level    : maze_def flags lev_init messages regions
  194.           {
  195.               int fout, i;
  196.  
  197.             if (fatal_error > 0) {
  198.                 fprintf(stderr,
  199.                   "%s : %d errors detected. No output created!\n",
  200.                     fname, fatal_error);
  201.             } else {
  202.                 char lbuf[20];
  203.                 Strcpy(lbuf, $1);
  204.                 Strcat(lbuf, LEV_EXT);
  205. #ifdef THINK_C
  206.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
  207. #else
  208.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
  209. #endif
  210.                 if (fout < 0) {
  211.                     yyerror("Can't open output file!!");
  212.                     exit(1);
  213.                 }
  214.                 maze.flags = $2;
  215.                 memcpy(&(maze.init_lev), &(init_lev),
  216.                        sizeof(lev_init));
  217.                 maze.numpart = npart;
  218.                 maze.parts = NewTab(mazepart, npart);
  219.                 for(i=0;i<npart;i++)
  220.                     maze.parts[i] = tmppart[i];
  221.                 write_maze(fout, &maze);
  222.                 (void) close(fout);
  223.                 npart = 0;
  224.             }
  225.           }
  226.         ;
  227.  
  228. room_level    : level_def flags lev_init messages rreg_init rooms corridors_def
  229.           {
  230.             int fout, i;
  231.  
  232.             if (fatal_error > 0) {
  233.                 fprintf(stderr,
  234.                   "%s : %d errors detected. No output created!\n",
  235.                     fname, fatal_error);
  236.             } else {
  237.                 char lbuf[20];
  238.                 Strcpy(lbuf, $1);
  239.                 Strcat(lbuf, LEV_EXT);
  240. #ifdef THINK_C
  241.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
  242. #else
  243.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
  244. #endif
  245.                 if (fout < 0) {
  246.                     yyerror("Can't open output file!!");
  247.                     exit(1);
  248.                 }
  249.                 special_lev.flags = $2;
  250.                 memcpy(&(special_lev.init_lev), &(init_lev),
  251.                        sizeof(lev_init));
  252.                 special_lev.nroom = nrooms;
  253.                 special_lev.rooms = NewTab(room, nrooms);
  254.                 for(i=0; i<nrooms; i++)
  255.                     special_lev.rooms[i] = tmproom[i];
  256.                 special_lev.ncorr = ncorridor;
  257.                 special_lev.corrs = NewTab(corridor, ncorridor);
  258.                 for(i=0; i<ncorridor; i++)
  259.                     special_lev.corrs[i] = tmpcor[i];
  260.                 if (check_subrooms())
  261.                     write_lev(fout, &special_lev);
  262.                 free_rooms(special_lev.rooms,special_lev.nroom);
  263.                 nrooms = 0;
  264.                 ncorridor = 0;
  265.                 (void) close(fout);
  266.             }
  267.           }
  268.         ;
  269.  
  270. level_def    : LEVEL_ID ':' string
  271.           {
  272.             if (index($3, '.'))
  273.                 yyerror("Invalid dot ('.') in level name.");
  274.             if (strlen($3) > 8)
  275.                 yyerror("Level names limited to 8 characters.");
  276.             $$ = $3;
  277.             special_lev.nrobjects = 0;
  278.             special_lev.nrmonst = 0;
  279.           }
  280.         ;
  281.  
  282. lev_init    : /* nothing */
  283.           {
  284.             init_lev.init_present = FALSE;
  285.             $$ = 0;
  286.           }
  287.         | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
  288.           {
  289.             init_lev.init_present = TRUE;
  290.             if((init_lev.fg = what_map_char($3)) == INVALID_TYPE)
  291.                 yyerror("Invalid foreground type.");
  292.             if((init_lev.bg = what_map_char($5)) == INVALID_TYPE)
  293.                 yyerror("Invalid background type.");
  294.             init_lev.smoothed = $7;
  295.             init_lev.joined = $9;
  296.             init_lev.lit = $11;
  297.             init_lev.walled = $13;
  298.             $$ = 1;
  299.           }
  300.         ;
  301.  
  302. walled        : BOOLEAN
  303.         | RANDOM_TYPE
  304.         ;
  305.  
  306. flags        : /* nothing */
  307.           {
  308.             $$ = 0;
  309.           }
  310.         | FLAGS_ID ':' flag_list
  311.           {
  312.             $$ = lev_flags;
  313.             lev_flags = 0;    /* clear for next user */
  314.           }
  315.         ;
  316.  
  317. flag_list    : FLAG_TYPE ',' flag_list
  318.           {
  319.             lev_flags |= $1;
  320.           }
  321.         | FLAG_TYPE
  322.           {
  323.             lev_flags |= $1;
  324.           }
  325.         ;
  326.  
  327. messages    : /* nothing */
  328.         | message messages
  329.         ;
  330.  
  331. message        : MESSAGE_ID ':' STRING
  332.           {
  333.             int i, j;
  334.  
  335.             i = strlen($3) + 1;
  336.             j = tmpmessage[0] ? strlen(tmpmessage) : 0;
  337.             if(i+j > 255) {
  338.                yyerror("Message string too long (>256 characters)");
  339.             } else {
  340.                 if(j) tmpmessage[j++] = '\n';
  341.                 strncpy(tmpmessage+j, $3, i-1);
  342.                 tmpmessage[j+i-1] = 0;
  343.             }
  344.           }
  345.         ;
  346.  
  347. rreg_init    : /* nothing */
  348.         | rreg_init init_rreg
  349.         ;
  350.  
  351. init_rreg    : RANDOM_OBJECTS_ID ':' object_list
  352.           {
  353.             if(special_lev.nrobjects) {
  354.                 yyerror("Object registers already initialized!");
  355.             } else {
  356.                 special_lev.nrobjects = n_olist;
  357.                 special_lev.robjects = (char *) alloc(n_olist);
  358.                 (void) memcpy((genericptr_t)special_lev.robjects,
  359.                       (genericptr_t)olist, n_olist);
  360.             }
  361.           }
  362.         | RANDOM_MONSTERS_ID ':' monster_list
  363.           {
  364.             if(special_lev.nrmonst) {
  365.                 yyerror("Monster registers already initialized!");
  366.             } else {
  367.                 special_lev.nrmonst = n_mlist;
  368.                 special_lev.rmonst = (char *) alloc(n_mlist);
  369.                 (void) memcpy((genericptr_t)special_lev.rmonst,
  370.                       (genericptr_t)mlist, n_mlist);
  371.               }
  372.           }
  373.         ;
  374.  
  375. rooms        : /* Nothing  -  dummy room for use with INIT_MAP */
  376.           {
  377.             tmproom[nrooms] = New(room);
  378.             (void) memset((genericptr_t) tmproom[nrooms], 0,
  379.                     sizeof *tmproom[nrooms]);
  380.             tmproom[nrooms]->name = (char *) 0;
  381.             tmproom[nrooms]->parent = (char *) 0;
  382.             tmproom[nrooms]->rtype = 0;
  383.             tmproom[nrooms]->rlit = 0;
  384.             tmproom[nrooms]->xalign = ERR;
  385.             tmproom[nrooms]->yalign = ERR;
  386.             tmproom[nrooms]->x = 0;
  387.             tmproom[nrooms]->y = 0;
  388.             tmproom[nrooms]->w = 2;
  389.             tmproom[nrooms]->h = 2;
  390.             in_room = 1;
  391.           }
  392.         | roomlist
  393.         ;
  394.  
  395. roomlist    : aroom
  396.         | aroom roomlist
  397.         ;
  398.  
  399. corridors_def    : random_corridors
  400.         | corridors
  401.         ;
  402.  
  403. random_corridors: RAND_CORRIDOR_ID
  404.           {
  405.             tmpcor[0] = New(corridor);
  406.             tmpcor[0]->src.room = -1;
  407.             ncorridor = 1;
  408.           }
  409.         ;
  410.  
  411. corridors    : /* nothing */
  412.         | corridors corridor
  413.         ;
  414.  
  415. corridor    : CORRIDOR_ID ':' corr_spec ',' corr_spec
  416.           {
  417.             tmpcor[ncorridor] = New(corridor);
  418.             tmpcor[ncorridor]->src.room = $3.room;
  419.             tmpcor[ncorridor]->src.wall = $3.wall;
  420.             tmpcor[ncorridor]->src.door = $3.door;
  421.             tmpcor[ncorridor]->dest.room = $5.room;
  422.             tmpcor[ncorridor]->dest.wall = $5.wall;
  423.             tmpcor[ncorridor]->dest.door = $5.door;
  424.             ncorridor++;
  425.           }
  426.         | CORRIDOR_ID ':' corr_spec ',' INTEGER
  427.           {
  428.             tmpcor[ncorridor]->src.room = $3.room;
  429.             tmpcor[ncorridor]->src.wall = $3.wall;
  430.             tmpcor[ncorridor]->src.door = $3.door;
  431.             tmpcor[ncorridor]->dest.room = -1;
  432.             tmpcor[ncorridor]->dest.wall = $5;
  433.             ncorridor++;
  434.           }
  435.         ;
  436.  
  437. corr_spec    : '(' INTEGER ',' DIRECTION ',' door_pos ')'
  438.           {
  439.             if ($2 >= nrooms)
  440.                 yyerror("Wrong room number!");
  441.             $$.room = $2;
  442.             $$.wall = $4;
  443.             $$.door = $6;
  444.           }
  445.         ;
  446.  
  447. aroom        : room_def room_details
  448.           {
  449.             store_room();
  450.           }
  451.         | subroom_def room_details
  452.           {
  453.             store_room();
  454.           }
  455.         ;
  456.  
  457. subroom_def    : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
  458.           {
  459.             tmproom[nrooms] = New(room);
  460.             (void) memset((genericptr_t) tmproom[nrooms], 0,
  461.                     sizeof *tmproom[nrooms]);
  462.             tmproom[nrooms]->parent = dup_string($11);
  463.             tmproom[nrooms]->name = (char *) 0;
  464.             tmproom[nrooms]->rtype = $3;
  465.             tmproom[nrooms]->rlit = $5;
  466.             tmproom[nrooms]->filled = $12;
  467.             tmproom[nrooms]->xalign = ERR;
  468.             tmproom[nrooms]->yalign = ERR;
  469.             tmproom[nrooms]->x = current_coord.x;
  470.             tmproom[nrooms]->y = current_coord.y;
  471.             tmproom[nrooms]->w = current_size.width;
  472.             tmproom[nrooms]->h = current_size.height;
  473.             in_room = 1;
  474.           }
  475.         ;
  476.  
  477. room_def    : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
  478.           {
  479.             tmproom[nrooms] = New(room);
  480.             (void) memset((genericptr_t) tmproom[nrooms], 0,
  481.                     sizeof *tmproom[nrooms]);
  482.             tmproom[nrooms]->name = (char *) 0;
  483.             tmproom[nrooms]->parent = (char *) 0;
  484.             tmproom[nrooms]->rtype = $3;
  485.             tmproom[nrooms]->rlit = $5;
  486.             tmproom[nrooms]->filled = $12;
  487.             tmproom[nrooms]->xalign = current_align.x;
  488.             tmproom[nrooms]->yalign = current_align.y;
  489.             tmproom[nrooms]->x = current_coord.x;
  490.             tmproom[nrooms]->y = current_coord.y;
  491.             tmproom[nrooms]->w = current_size.width;
  492.             tmproom[nrooms]->h = current_size.height;
  493.             in_room = 1;
  494.           }
  495.         ;
  496.  
  497. roomfill    : /* nothing */
  498.           {
  499.             $$ = 1;
  500.           }
  501.         | ',' BOOLEAN
  502.           {
  503.             $$ = $2;
  504.           }
  505.         ;
  506.  
  507. room_pos    : '(' INTEGER ',' INTEGER ')'
  508.           {
  509.             if ( $2 < 1 || $2 > 5 ||
  510.                 $4 < 1 || $4 > 5 ) {
  511.                 yyerror("Room position should be between 1 & 5!");
  512.             } else {
  513.                 current_coord.x = $2;
  514.                 current_coord.y = $4;
  515.             }
  516.           }
  517.         | RANDOM_TYPE
  518.           {
  519.             current_coord.x = current_coord.y = ERR;
  520.           }
  521.         ;
  522.  
  523. subroom_pos    : '(' INTEGER ',' INTEGER ')'
  524.           {
  525.             if ( $2 < 0 || $4 < 0) {
  526.                 yyerror("Invalid subroom position !");
  527.             } else {
  528.                 current_coord.x = $2;
  529.                 current_coord.y = $4;
  530.             }
  531.           }
  532.         | RANDOM_TYPE
  533.           {
  534.             current_coord.x = current_coord.y = ERR;
  535.           }
  536.         ;
  537.  
  538. room_align    : '(' h_justif ',' v_justif ')'
  539.           {
  540.             current_align.x = $2;
  541.             current_align.y = $4;
  542.           }
  543.         | RANDOM_TYPE
  544.           {
  545.             current_align.x = current_align.y = ERR;
  546.           }
  547.         ;
  548.  
  549. room_size    : '(' INTEGER ',' INTEGER ')'
  550.           {
  551.             current_size.width = $2;
  552.             current_size.height = $4;
  553.           }
  554.         | RANDOM_TYPE
  555.           {
  556.             current_size.height = current_size.width = ERR;
  557.           }
  558.         ;
  559.  
  560. room_details    : /* nothing */
  561.         | room_details room_detail
  562.         ;
  563.  
  564. room_detail    : room_name
  565.         | room_chance
  566.         | room_door
  567.         | monster_detail
  568.         | object_detail
  569.         | trap_detail
  570.         | altar_detail
  571.         | fountain_detail
  572.         | sink_detail
  573.         | pool_detail
  574.         | gold_detail
  575.         | engraving_detail
  576.         | stair_detail
  577.         ;
  578.  
  579. room_name    : NAME_ID ':' string
  580.           {
  581.             if (tmproom[nrooms]->name)
  582.                 yyerror("This room already has a name!");
  583.             else
  584.                 tmproom[nrooms]->name = dup_string($3);
  585.           }
  586.         ;
  587.  
  588. room_chance    : CHANCE_ID ':' INTEGER
  589.            {
  590.             if (tmproom[nrooms]->chance)
  591.                 yyerror("This room already assigned a chance!");
  592.             else if (tmproom[nrooms]->rtype == OROOM)
  593.                 yyerror("Only typed rooms can have a chance!");
  594.             else if ($3 < 1 || $3 > 99)
  595.                 yyerror("The chance is supposed to be precentile.");
  596.             else
  597.                 tmproom[nrooms]->chance = $3;
  598.            }
  599.         ;
  600.  
  601. room_door    : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
  602.           {
  603.             /* ERR means random here */
  604.             if ($7 == ERR && $9 != ERR) {
  605.              yyerror("If the door wall is random, so must be its pos!");
  606.             } else {
  607.                 tmprdoor[ndoor] = New(room_door);
  608.                 tmprdoor[ndoor]->secret = $3;
  609.                 tmprdoor[ndoor]->mask = $5;
  610.                 tmprdoor[ndoor]->wall = $7;
  611.                 tmprdoor[ndoor]->pos = $9;
  612.                 ndoor++;
  613.             }
  614.           }
  615.         ;
  616.  
  617. secret        : BOOLEAN
  618.         | RANDOM_TYPE
  619.         ;
  620.  
  621. door_wall    : DIRECTION
  622.         | RANDOM_TYPE
  623.         ;
  624.  
  625. door_pos    : INTEGER
  626.         | RANDOM_TYPE
  627.         ;
  628.  
  629. maze_def    : MAZE_ID ':' string ',' filling
  630.           {
  631.             maze.filling = $5;
  632.             if (index($3, '.'))
  633.                 yyerror("Invalid dot ('.') in level name.");
  634.             if (strlen($3) > 8)
  635.                 yyerror("Level names limited to 8 characters.");
  636.             $$ = $3;
  637.             in_room = 0;
  638.           }
  639.         ;
  640.  
  641. filling        : CHAR
  642.           {
  643.             $$ = get_floor_type((char)$1);
  644.           }
  645.         | RANDOM_TYPE
  646.           {
  647.             $$ = -1;
  648.           }
  649.         ;
  650.  
  651. regions        : aregion
  652.         | aregion regions
  653.         ;
  654.  
  655. aregion        : map_definition reg_init map_details
  656.           {
  657.             store_part();
  658.           }
  659.         ;
  660.  
  661. map_definition    : NOMAP_ID
  662.           {
  663.             tmppart[npart] = New(mazepart);
  664.             tmppart[npart]->halign = 1;
  665.             tmppart[npart]->valign = 1;
  666.             tmppart[npart]->nrobjects = 0;
  667.             tmppart[npart]->nloc = 0;
  668.             tmppart[npart]->nrmonst = 0;
  669.             tmppart[npart]->xsize = 1;
  670.             tmppart[npart]->ysize = 1;
  671.             tmppart[npart]->map = (char **) alloc(sizeof(char *));
  672.             tmppart[npart]->map[0] = (char *) alloc(1);
  673.             tmppart[npart]->map[0][0] = STONE;
  674.             max_x_map = COLNO-1;
  675.             max_y_map = ROWNO;
  676.           }
  677.         | map_geometry MAP_ID
  678.           {
  679.             tmppart[npart] = New(mazepart);
  680.             tmppart[npart]->halign = $<i>1 % 10;
  681.             tmppart[npart]->valign = $<i>1 / 10;
  682.             tmppart[npart]->nrobjects = 0;
  683.             tmppart[npart]->nloc = 0;
  684.             tmppart[npart]->nrmonst = 0;
  685.             scan_map($2);
  686.           }
  687.         ;
  688.  
  689. map_geometry    : GEOMETRY_ID ':' h_justif ',' v_justif
  690.           {
  691.             $<i>$ = $<i>3 + ($<i>5 * 10);
  692.           }
  693.         ;
  694.  
  695. h_justif    : LEFT_OR_RIGHT
  696.         | CENTER
  697.         ;
  698.  
  699. v_justif    : TOP_OR_BOT
  700.         | CENTER
  701.         ;
  702.  
  703. reg_init    : /* nothing */
  704.         | reg_init init_reg
  705.         ;
  706.  
  707. init_reg    : RANDOM_OBJECTS_ID ':' object_list
  708.           {
  709.             if (tmppart[npart]->nrobjects) {
  710.                 yyerror("Object registers already initialized!");
  711.             } else {
  712.                 tmppart[npart]->robjects = (char *)alloc(n_olist);
  713.                 (void) memcpy((genericptr_t)tmppart[npart]->robjects,
  714.                       (genericptr_t)olist, n_olist);
  715.                 tmppart[npart]->nrobjects = n_olist;
  716.             }
  717.           }
  718.         | RANDOM_PLACES_ID ':' place_list
  719.           {
  720.             if (tmppart[npart]->nloc) {
  721.                 yyerror("Location registers already initialized!");
  722.             } else {
  723.                 register int i;
  724.                 tmppart[npart]->rloc_x = (char *) alloc(n_plist);
  725.                 tmppart[npart]->rloc_y = (char *) alloc(n_plist);
  726.                 for(i=0;i<n_plist;i++) {
  727.                 tmppart[npart]->rloc_x[i] = plist[i].x;
  728.                 tmppart[npart]->rloc_y[i] = plist[i].y;
  729.                 }
  730.                 tmppart[npart]->nloc = n_plist;
  731.             }
  732.           }
  733.         | RANDOM_MONSTERS_ID ':' monster_list
  734.           {
  735.             if (tmppart[npart]->nrmonst) {
  736.                 yyerror("Monster registers already initialized!");
  737.             } else {
  738.                 tmppart[npart]->rmonst = (char *) alloc(n_mlist);
  739.                 (void) memcpy((genericptr_t)tmppart[npart]->rmonst,
  740.                       (genericptr_t)mlist, n_mlist);
  741.                 tmppart[npart]->nrmonst = n_mlist;
  742.             }
  743.           }
  744.         ;
  745.  
  746. object_list    : object
  747.           {
  748.             if (n_olist < MAX_REGISTERS)
  749.                 olist[n_olist++] = $<i>1;
  750.             else
  751.                 yyerror("Object list too long!");
  752.           }
  753.         | object ',' object_list
  754.           {
  755.             if (n_olist < MAX_REGISTERS)
  756.                 olist[n_olist++] = $<i>1;
  757.             else
  758.                 yyerror("Object list too long!");
  759.           }
  760.         ;
  761.  
  762. monster_list    : monster
  763.           {
  764.             if (n_mlist < MAX_REGISTERS)
  765.                 mlist[n_mlist++] = $<i>1;
  766.             else
  767.                 yyerror("Monster list too long!");
  768.           }
  769.         | monster ',' monster_list
  770.           {
  771.             if (n_mlist < MAX_REGISTERS)
  772.                 mlist[n_mlist++] = $<i>1;
  773.             else
  774.                 yyerror("Monster list too long!");
  775.           }
  776.         ;
  777.  
  778. place_list    : place
  779.           {
  780.             if (n_plist < MAX_REGISTERS)
  781.                 plist[n_plist++] = current_coord;
  782.             else
  783.                 yyerror("Location list too long!");
  784.           }
  785.         | place
  786.           {
  787.             if (n_plist < MAX_REGISTERS)
  788.                 plist[n_plist++] = current_coord;
  789.             else
  790.                 yyerror("Location list too long!");
  791.           }
  792.          ',' place_list
  793.         ;
  794.  
  795. map_details    : /* nothing */
  796.         | map_details map_detail
  797.         ;
  798.  
  799. map_detail    : monster_detail
  800.         | object_detail
  801.         | door_detail
  802.         | trap_detail
  803.         | drawbridge_detail
  804.         | region_detail
  805.         | stair_region
  806.         | portal_region
  807.         | teleprt_region
  808.         | branch_region
  809.         | altar_detail
  810.         | fountain_detail
  811.         | mazewalk_detail
  812.         | wallify_detail
  813.         | ladder_detail
  814.         | stair_detail
  815.         | gold_detail
  816.         | engraving_detail
  817.         | diggable_detail
  818.         | passwall_detail
  819.         ;
  820.  
  821. monster_detail    : MONSTER_ID ':' monster_c ',' m_name ',' coordinate
  822.           {
  823.             tmpmonst[nmons] = New(monster);
  824.             tmpmonst[nmons]->x = current_coord.x;
  825.             tmpmonst[nmons]->y = current_coord.y;
  826.             tmpmonst[nmons]->class = $<i>3;
  827.             tmpmonst[nmons]->peaceful = -1; /* no override */
  828.             tmpmonst[nmons]->asleep = -1;
  829.             tmpmonst[nmons]->align = - MAX_REGISTERS - 2;
  830.             tmpmonst[nmons]->name = (char *) 0;
  831.             tmpmonst[nmons]->appear = 0;
  832.             tmpmonst[nmons]->appear_as = (char *) 0;
  833.             if (!in_room)
  834.                 check_coord(current_coord.x, current_coord.y,
  835.                     "Monster");
  836.             if (!$5)
  837.                 tmpmonst[nmons]->id = -1;
  838.             else {
  839.                 int token = get_monster_id($5, (char) $<i>3);
  840.                 if (token == ERR) {
  841.                     yywarning("Illegal monster name!  Making random monster.");
  842.                     tmpmonst[nmons]->id = -1;
  843.                 } else
  844.                     tmpmonst[nmons]->id = token;
  845.             }
  846.           }
  847.          monster_infos
  848.           {
  849.             nmons++;
  850.           }
  851.         ;
  852.  
  853. monster_infos    : /* nothing */
  854.         | monster_infos monster_info
  855.         ;
  856.  
  857. monster_info    : ',' string
  858.           {
  859.             tmpmonst[nmons]->name = dup_string($2);
  860.           }
  861.         | ',' MON_ATTITUDE
  862.           {
  863.             tmpmonst[nmons]->peaceful = $<i>2;
  864.           }
  865.         | ',' MON_ALERTNESS
  866.           {
  867.             tmpmonst[nmons]->asleep = $<i>2;
  868.           }
  869.         | ',' alignment
  870.           {
  871.             tmpmonst[nmons]->align = $<i>2;
  872.           }
  873.         | ',' MON_APPEARANCE string
  874.           {
  875.             tmpmonst[nmons]->appear = $<i>2;
  876.             tmpmonst[nmons]->appear_as = dup_string($3);
  877.           }
  878.         ;
  879.  
  880. object_detail    : OBJECT_ID ':' object_c ',' o_name ',' coordinate
  881.           {
  882.             tmpobj[nobj] = New(object);
  883.             tmpobj[nobj]->x = current_coord.x;
  884.             tmpobj[nobj]->y = current_coord.y;
  885.             tmpobj[nobj]->class = $<i>3;
  886.             tmpobj[nobj]->corpsenm = -1;    /* init as none */
  887.             tmpobj[nobj]->curse_state = -1;
  888.             tmpobj[nobj]->name = (char *) 0;
  889.             if (!in_room)
  890.                 check_coord(current_coord.x, current_coord.y,
  891.                     "Object");
  892.             if (!$5)
  893.                 tmpobj[nobj]->id = -1;
  894.             else {
  895.                 int token = get_object_id($5);
  896.                 if (token == ERR) {
  897.                     yywarning("Illegal object name!  Making random object.");
  898.                     tmpobj[nobj]->id = -1;
  899.                 } else
  900.                     tmpobj[nobj]->id = token;
  901.             }
  902.           }
  903.          object_infos
  904.           {
  905.             nobj++;
  906.           }
  907.         ;
  908.  
  909. object_infos    : /* nothing */
  910.           {
  911.             tmpobj[nobj]->spe = -127;
  912.           }
  913.         | ',' STRING ',' enchantment
  914.           {
  915.             int token = get_monster_id($2, (char)0);
  916.             if (token == ERR)    /* "random" */
  917.                 tmpobj[nobj]->corpsenm = -2;
  918.             else
  919.                 tmpobj[nobj]->corpsenm = token;
  920.             tmpobj[nobj]->spe = $<i>4;
  921.           }
  922.         | ',' curse_state ',' enchantment ',' art_name
  923.           {
  924.             tmpobj[nobj]->curse_state = $<i>2;
  925.             tmpobj[nobj]->spe = $<i>4;
  926.             if ($6)
  927.                 tmpobj[nobj]->name = dup_string($6);
  928.             else
  929.                 tmpobj[nobj]->name = (char *) 0;
  930.           }
  931.         ;
  932.  
  933. curse_state    : RANDOM_TYPE
  934.         | CURSE_TYPE
  935.         ;
  936.  
  937. enchantment    : INTEGER
  938.         | RANDOM_TYPE
  939.           {
  940.             $<i>$ = -127;
  941.           }
  942.         ;
  943.  
  944. door_detail    : DOOR_ID ':' door_state ',' coordinate
  945.           {
  946.             tmpdoor[ndoor] = New(door);
  947.             tmpdoor[ndoor]->x = current_coord.x;
  948.             tmpdoor[ndoor]->y = current_coord.y;
  949.             tmpdoor[ndoor]->mask = $<i>3;
  950.             if(current_coord.x >= 0 && current_coord.y >= 0 &&
  951.                tmpmap[current_coord.y][current_coord.x] != DOOR &&
  952.                tmpmap[current_coord.y][current_coord.x] != SDOOR)
  953.                 yyerror("Door decl doesn't match the map");
  954.             ndoor++;
  955.           }
  956.         ;
  957.  
  958. trap_detail    : TRAP_ID ':' trap_name ',' coordinate
  959.           {
  960.             tmptrap[ntrap] = New(trap);
  961.             tmptrap[ntrap]->x = current_coord.x;
  962.             tmptrap[ntrap]->y = current_coord.y;
  963.             tmptrap[ntrap]->type = $<i>3;
  964.             if (!in_room)
  965.                 check_coord(current_coord.x, current_coord.y,
  966.                     "Trap");
  967.             ntrap++;
  968.           }
  969.         ;
  970.  
  971. drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
  972.            {
  973.                 int x, y, dir;
  974.  
  975.             tmpdb[ndb] = New(drawbridge);
  976.             x = tmpdb[ndb]->x = current_coord.x;
  977.             y = tmpdb[ndb]->y = current_coord.y;
  978.             /* convert dir from a DIRECTION to a DB_DIR */
  979.             dir = $5;
  980.             switch(dir) {
  981.             case W_NORTH: dir = DB_NORTH; y--; break;
  982.             case W_SOUTH: dir = DB_SOUTH; y++; break;
  983.             case W_EAST:  dir = DB_EAST;  x++; break;
  984.             case W_WEST:  dir = DB_WEST;  x--; break;
  985.             default:
  986.                 yyerror("Invalid drawbridge direction");
  987.                 break;
  988.             }
  989.             tmpdb[ndb]->dir = dir;
  990.             if (current_coord.x >= 0 && current_coord.y >= 0 &&
  991.                 !IS_WALL(tmpmap[y][x])) {
  992.                 char ebuf[60];
  993.                 Sprintf(ebuf,
  994.                     "Wall needed for drawbridge (%02d, %02d)",
  995.                     current_coord.x, current_coord.y);
  996.                 yyerror(ebuf);
  997.             }
  998.  
  999.             if ( $<i>7 == D_ISOPEN )
  1000.                 tmpdb[ndb]->db_open = 1;
  1001.             else if ( $<i>7 == D_CLOSED )
  1002.                 tmpdb[ndb]->db_open = 0;
  1003.             else
  1004.                 yyerror("A drawbridge can only be open or closed!");
  1005.             ndb++;
  1006.            }
  1007.         ;
  1008.  
  1009. mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
  1010.           {
  1011.             tmpwalk[nwalk] = New(walk);
  1012.             tmpwalk[nwalk]->x = current_coord.x;
  1013.             tmpwalk[nwalk]->y = current_coord.y;
  1014.             tmpwalk[nwalk]->dir = $5;
  1015.             nwalk++;
  1016.           }
  1017.         ;
  1018.  
  1019. wallify_detail    : WALLIFY_ID
  1020.           {
  1021.             wallify_map();
  1022.           }
  1023.         ;
  1024.  
  1025. ladder_detail    : LADDER_ID ':' coordinate ',' UP_OR_DOWN
  1026.           {
  1027.             tmplad[nlad] = New(lad);
  1028.             tmplad[nlad]->x = current_coord.x;
  1029.             tmplad[nlad]->y = current_coord.y;
  1030.             tmplad[nlad]->up = $<i>5;
  1031.             if (!in_room)
  1032.                 check_coord(current_coord.x, current_coord.y,
  1033.                     "Ladder");
  1034.             nlad++;
  1035.           }
  1036.         ;
  1037.  
  1038. stair_detail    : STAIR_ID ':' coordinate ',' UP_OR_DOWN
  1039.           {
  1040.             tmpstair[nstair] = New(stair);
  1041.             tmpstair[nstair]->x = current_coord.x;
  1042.             tmpstair[nstair]->y = current_coord.y;
  1043.             tmpstair[nstair]->up = $<i>5;
  1044.             if (!in_room)
  1045.                 check_coord(current_coord.x, current_coord.y,
  1046.                     "Stairway");
  1047.             nstair++;
  1048.           }
  1049.         ;
  1050.  
  1051. stair_region    : STAIR_ID ':' lev_region
  1052.           {
  1053.             tmplreg[nlreg] = New(lev_region);
  1054.             tmplreg[nlreg]->in_islev = $3;
  1055.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1056.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1057.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1058.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1059.           }
  1060.          ',' lev_region ',' UP_OR_DOWN
  1061.           {
  1062.             tmplreg[nlreg]->del_islev = $6;
  1063.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1064.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1065.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1066.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1067.             if($8)
  1068.                 tmplreg[nlreg]->rtype = LR_UPSTAIR;
  1069.             else
  1070.                 tmplreg[nlreg]->rtype = LR_DOWNSTAIR;
  1071.             tmplreg[nlreg]->rname = 0;
  1072.             nlreg++;
  1073.           }
  1074.         ;
  1075.  
  1076. portal_region    : PORTAL_ID ':' lev_region
  1077.           {
  1078.             tmplreg[nlreg] = New(lev_region);
  1079.             tmplreg[nlreg]->in_islev = $3;
  1080.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1081.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1082.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1083.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1084.           }
  1085.          ',' lev_region ',' string
  1086.           {
  1087.             tmplreg[nlreg]->del_islev = $6;
  1088.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1089.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1090.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1091.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1092.             tmplreg[nlreg]->rtype = LR_PORTAL;
  1093.             tmplreg[nlreg]->rname = $8;
  1094.             nlreg++;
  1095.           }
  1096.         ;
  1097.  
  1098. teleprt_region    : TELEPRT_ID ':' lev_region
  1099.           {
  1100.             tmplreg[nlreg] = New(lev_region);
  1101.             tmplreg[nlreg]->in_islev = $3;
  1102.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1103.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1104.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1105.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1106.           }
  1107.          ',' lev_region
  1108.           {
  1109.             tmplreg[nlreg]->del_islev = $6;
  1110.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1111.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1112.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1113.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1114.           }
  1115.         teleprt_detail
  1116.           {
  1117.             switch($<i>8) {
  1118.             case -1: tmplreg[nlreg]->rtype = LR_TELE; break;
  1119.             case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break;
  1120.             case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break;
  1121.             }
  1122.             tmplreg[nlreg]->rname = 0;
  1123.             nlreg++;
  1124.           }
  1125.         ;
  1126.  
  1127. branch_region    : BRANCH_ID ':' lev_region
  1128.           {
  1129.             tmplreg[nlreg] = New(lev_region);
  1130.             tmplreg[nlreg]->in_islev = $3;
  1131.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1132.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1133.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1134.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1135.           }
  1136.          ',' lev_region
  1137.           {
  1138.             tmplreg[nlreg]->del_islev = $6;
  1139.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1140.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1141.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1142.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1143.             tmplreg[nlreg]->rtype = LR_BRANCH;
  1144.             tmplreg[nlreg]->rname = 0;
  1145.             nlreg++;
  1146.           }
  1147.         ;
  1148.  
  1149. teleprt_detail    : /* empty */
  1150.           {
  1151.             $<i>$ = -1;
  1152.           }
  1153.         | ',' UP_OR_DOWN
  1154.           {
  1155.             $<i>$ = $2;
  1156.           }
  1157.         ;
  1158.  
  1159. lev_region    : region
  1160.           {
  1161.             $$ = 0;
  1162.           }
  1163.         | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
  1164.           {
  1165. /* This series of if statements is a hack for MSC 5.1.  It seems that its
  1166.    tiny little brain cannot compile if these are all one big if statement. */
  1167.             if ($3 <= 0 || $3 >= COLNO)
  1168.                 yyerror("Region out of level range!");
  1169.             else if ($5 < 0 || $5 >= ROWNO)
  1170.                 yyerror("Region out of level range!");
  1171.             else if ($7 <= 0 || $7 >= COLNO)
  1172.                 yyerror("Region out of level range!");
  1173.             else if ($9 < 0 || $9 >= ROWNO)
  1174.                 yyerror("Region out of level range!");
  1175.             current_region.x1 = $3;
  1176.             current_region.y1 = $5;
  1177.             current_region.x2 = $7;
  1178.             current_region.y2 = $9;
  1179.             $$ = 1;
  1180.           }
  1181.         ;
  1182.  
  1183. fountain_detail : FOUNTAIN_ID ':' coordinate
  1184.           {
  1185.             tmpfountain[nfountain] = New(fountain);
  1186.             tmpfountain[nfountain]->x = current_coord.x;
  1187.             tmpfountain[nfountain]->y = current_coord.y;
  1188.             if (!in_room)
  1189.                 check_coord(current_coord.x, current_coord.y,
  1190.                     "Fountain");
  1191.             nfountain++;
  1192.           }
  1193.         ;
  1194.  
  1195. sink_detail : SINK_ID ':' coordinate
  1196.           {
  1197.             tmpsink[nsink] = New(sink);
  1198.             tmpsink[nsink]->x = current_coord.x;
  1199.             tmpsink[nsink]->y = current_coord.y;
  1200.             nsink++;
  1201.           }
  1202.         ;
  1203.  
  1204. pool_detail : POOL_ID ':' coordinate
  1205.           {
  1206.             tmppool[npool] = New(pool);
  1207.             tmppool[npool]->x = current_coord.x;
  1208.             tmppool[npool]->y = current_coord.y;
  1209.             npool++;
  1210.           }
  1211.         ;
  1212.  
  1213. diggable_detail : NON_DIGGABLE_ID ':' region
  1214.           {
  1215.             tmpdig[ndig] = New(digpos);
  1216.             tmpdig[ndig]->x1 = current_region.x1;
  1217.             tmpdig[ndig]->y1 = current_region.y1;
  1218.             tmpdig[ndig]->x2 = current_region.x2;
  1219.             tmpdig[ndig]->y2 = current_region.y2;
  1220.             ndig++;
  1221.           }
  1222.         ;
  1223.  
  1224. passwall_detail : NON_PASSWALL_ID ':' region
  1225.           {
  1226.             tmppass[npass] = New(digpos);
  1227.             tmppass[npass]->x1 = current_region.x1;
  1228.             tmppass[npass]->y1 = current_region.y1;
  1229.             tmppass[npass]->x2 = current_region.x2;
  1230.             tmppass[npass]->y2 = current_region.y2;
  1231.             npass++;
  1232.           }
  1233.         ;
  1234.  
  1235. region_detail    : REGION_ID ':' region ',' light_state ',' room_type prefilled
  1236.           {
  1237.             tmpreg[nreg] = New(region);
  1238.             tmpreg[nreg]->x1 = current_region.x1;
  1239.             tmpreg[nreg]->y1 = current_region.y1;
  1240.             tmpreg[nreg]->x2 = current_region.x2;
  1241.             tmpreg[nreg]->y2 = current_region.y2;
  1242.             tmpreg[nreg]->rlit = $<i>5;
  1243.             tmpreg[nreg]->rtype = $<i>7;
  1244.             if($<i>8 & 1) tmpreg[nreg]->rtype += MAXRTYPE+1;
  1245.             tmpreg[nreg]->rirreg = (($<i>8 & 2) != 0);
  1246.             if(current_region.x1 > current_region.x2 ||
  1247.                current_region.y1 > current_region.y2)
  1248.                yyerror("Region start > end!");
  1249.             if(tmpreg[nreg]->rtype == VAULT &&
  1250.                (tmpreg[nreg]->rirreg ||
  1251.                 (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) ||
  1252.                 (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1)))
  1253.                 yyerror("Vaults must be exactly 2x2!");
  1254.             if(want_warnings && !tmpreg[nreg]->rirreg &&
  1255.                current_region.x1 > 0 && current_region.y1 > 0 &&
  1256.                current_region.x2 < max_x_map &&
  1257.                current_region.y2 < max_y_map) {
  1258.                 /* check for walls in the room */
  1259.                 char ebuf[60];
  1260.                 register int x, y, nrock = 0;
  1261.  
  1262.                 for(y=current_region.y1; y<=current_region.y2; y++)
  1263.                 for(x=current_region.x1;
  1264.                     x<=current_region.x2; x++)
  1265.                     if(IS_ROCK(tmpmap[y][x]) ||
  1266.                        IS_DOOR(tmpmap[y][x])) nrock++;
  1267.                 if(nrock) {
  1268.                 Sprintf(ebuf,
  1269.                     "Rock in room (%02d,%02d,%02d,%02d)?!",
  1270.                     current_region.x1, current_region.y1,
  1271.                     current_region.x2, current_region.y2);
  1272.                 yywarning(ebuf);
  1273.                 }
  1274.                 if (
  1275.         !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) ||
  1276.         !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) ||
  1277.         !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) ||
  1278.         !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) {
  1279.                 Sprintf(ebuf,
  1280.                 "NonRock edge in room (%02d,%02d,%02d,%02d)?!",
  1281.                     current_region.x1, current_region.y1,
  1282.                     current_region.x2, current_region.y2);
  1283.                 yywarning(ebuf);
  1284.                 }
  1285.             } else if(tmpreg[nreg]->rirreg &&
  1286.         !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) {
  1287.                 char ebuf[60];
  1288.                 Sprintf(ebuf,
  1289.                     "Rock in irregular room (%02d,%02d)?!",
  1290.                     current_region.x1, current_region.y1);
  1291.                 yyerror(ebuf);
  1292.             }
  1293.             nreg++;
  1294.           }
  1295.         ;
  1296.  
  1297. altar_detail    : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
  1298.           {
  1299.             tmpaltar[naltar] = New(altar);
  1300.             tmpaltar[naltar]->x = current_coord.x;
  1301.             tmpaltar[naltar]->y = current_coord.y;
  1302.             tmpaltar[naltar]->align = $<i>5;
  1303.             tmpaltar[naltar]->shrine = $<i>7;
  1304.             if (!in_room)
  1305.                 check_coord(current_coord.x, current_coord.y,
  1306.                     "Altar");
  1307.             naltar++;
  1308.           }
  1309.         ;
  1310.  
  1311. gold_detail    : GOLD_ID ':' amount ',' coordinate
  1312.           {
  1313.             tmpgold[ngold] = New(gold);
  1314.             tmpgold[ngold]->x = current_coord.x;
  1315.             tmpgold[ngold]->y = current_coord.y;
  1316.             tmpgold[ngold]->amount = $<i>3;
  1317.             if (!in_room)
  1318.                 check_coord(current_coord.x, current_coord.y,
  1319.                     "Gold");
  1320.             ngold++;
  1321.           }
  1322.         ;
  1323.  
  1324. engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
  1325.           {
  1326.             tmpengraving[nengraving] = New(engraving);
  1327.             tmpengraving[nengraving]->x = current_coord.x;
  1328.             tmpengraving[nengraving]->y = current_coord.y;
  1329.             tmpengraving[nengraving]->e.text = $7;
  1330.             tmpengraving[nengraving]->etype = $<i>5;
  1331.             if (!in_room)
  1332.                 check_coord(current_coord.x, current_coord.y,
  1333.                     "Engraving");
  1334.             nengraving++;
  1335.           }
  1336.         ;
  1337.  
  1338. monster_c    : monster
  1339.         | RANDOM_TYPE
  1340.           {
  1341.             $<i>$ = - MAX_REGISTERS - 1;
  1342.           }
  1343.         | m_register
  1344.         ;
  1345.  
  1346. object_c    : object
  1347.         | RANDOM_TYPE
  1348.           {
  1349.             $<i>$ = - MAX_REGISTERS - 1;
  1350.           }
  1351.         | o_register
  1352.         ;
  1353.  
  1354. m_name        : string
  1355.         | RANDOM_TYPE
  1356.           {
  1357.             $$ = (char *) 0;
  1358.           }
  1359.         ;
  1360.  
  1361. o_name        : string
  1362.         | RANDOM_TYPE
  1363.           {
  1364.             $$ = (char *) 0;
  1365.           }
  1366.         ;
  1367.  
  1368. trap_name    : string
  1369.           {
  1370.             int token = get_trap_type($1);
  1371.             if (token == ERR)
  1372.                 yyerror("Unknown trap type!");
  1373.             $<i>$ = token;
  1374.           }
  1375.         | RANDOM_TYPE
  1376.         ;
  1377.  
  1378. room_type    : string
  1379.           {
  1380.             int token = get_room_type($1);
  1381.             if (token == ERR) {
  1382.                 yywarning("Unknown room type!  Making ordinary room...");
  1383.                 $<i>$ = OROOM;
  1384.             } else
  1385.                 $<i>$ = token;
  1386.           }
  1387.         | RANDOM_TYPE
  1388.         ;
  1389.  
  1390. prefilled    : /* empty */
  1391.           {
  1392.             $<i>$ = 0;
  1393.           }
  1394.         | ',' FILLING
  1395.           {
  1396.             $<i>$ = $2;
  1397.           }
  1398.         | ',' FILLING ',' BOOLEAN
  1399.           {
  1400.             $<i>$ = $2 + ($4 << 1);
  1401.           }
  1402.         ;
  1403.  
  1404. coordinate    : coord
  1405.         | p_register
  1406.         | RANDOM_TYPE
  1407.           {
  1408.             current_coord.x = current_coord.y = -MAX_REGISTERS-1;
  1409.           }
  1410.         ;
  1411.  
  1412. door_state    : DOOR_STATE
  1413.         | RANDOM_TYPE
  1414.         ;
  1415.  
  1416. light_state    : LIGHT_STATE
  1417.         | RANDOM_TYPE
  1418.         ;
  1419.  
  1420. alignment    : ALIGNMENT
  1421.         | a_register
  1422.         | RANDOM_TYPE
  1423.           {
  1424.             $<i>$ = - MAX_REGISTERS - 1;
  1425.           }
  1426.         ;
  1427.  
  1428. altar_type    : ALTAR_TYPE
  1429.         | RANDOM_TYPE
  1430.         ;
  1431.  
  1432. p_register    : P_REGISTER '[' INTEGER ']'
  1433.           {
  1434.             if ( $3 >= MAX_REGISTERS )
  1435.                 yyerror("Register Index overflow!");
  1436.             else
  1437.                 current_coord.x = current_coord.y = - $3 - 1;
  1438.           }
  1439.         ;
  1440.  
  1441. o_register    : O_REGISTER '[' INTEGER ']'
  1442.           {
  1443.             if ( $3 >= MAX_REGISTERS )
  1444.                 yyerror("Register Index overflow!");
  1445.             else
  1446.                 $<i>$ = - $3 - 1;
  1447.           }
  1448.         ;
  1449.  
  1450. m_register    : M_REGISTER '[' INTEGER ']'
  1451.           {
  1452.             if ( $3 >= MAX_REGISTERS )
  1453.                 yyerror("Register Index overflow!");
  1454.             else
  1455.                 $<i>$ = - $3 - 1;
  1456.           }
  1457.         ;
  1458.  
  1459. a_register    : A_REGISTER '[' INTEGER ']'
  1460.           {
  1461.             if ( $3 >= 3 )
  1462.                 yyerror("Register Index overflow!");
  1463.             else
  1464.                 $<i>$ = - $3 - 1;
  1465.           }
  1466.         ;
  1467.  
  1468. place        : coord
  1469.         ;
  1470.  
  1471. monster        : CHAR
  1472.           {
  1473.             if (check_monster_char((char) $1))
  1474.                 $<i>$ = $1 ;
  1475.             else {
  1476.                 yyerror("Unknown monster class!");
  1477.                 $<i>$ = ERR;
  1478.             }
  1479.           }
  1480.         ;
  1481.  
  1482. object        : CHAR
  1483.           {
  1484.             char c = $1;
  1485.             if (check_object_char(c))
  1486.                 $<i>$ = c;
  1487.             else {
  1488.                 yyerror("Unknown char class!");
  1489.                 $<i>$ = ERR;
  1490.             }
  1491.           }
  1492.         ;
  1493.  
  1494. string        : STRING
  1495.         ;
  1496.  
  1497. art_name    : STRING
  1498.         | NONE
  1499.           {
  1500.             $$ = (char *) 0;
  1501.           }
  1502.         ;
  1503.  
  1504. amount        : INTEGER
  1505.         | RANDOM_TYPE
  1506.         ;
  1507.  
  1508. engraving_type    : ENGRAVING_TYPE
  1509.         | RANDOM_TYPE
  1510.         ;
  1511.  
  1512. coord        : '(' INTEGER ',' INTEGER ')'
  1513.           {
  1514.             if (!in_room && !init_lev.init_present &&
  1515.                 ($2 < 0 || $2 > max_x_map ||
  1516.                  $4 < 0 || $4 > max_y_map))
  1517.                 yyerror("Coordinates out of map range!");
  1518.             current_coord.x = $2;
  1519.             current_coord.y = $4;
  1520.           }
  1521.         ;
  1522.  
  1523. region        : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
  1524.           {
  1525. /* This series of if statements is a hack for MSC 5.1.  It seems that its
  1526.    tiny little brain cannot compile if these are all one big if statement. */
  1527.             if ($2 < 0 || $2 > max_x_map)
  1528.                 yyerror("Region out of map range!");
  1529.             else if ($4 < 0 || $4 > max_y_map)
  1530.                 yyerror("Region out of map range!");
  1531.             else if ($6 < 0 || $6 > max_x_map)
  1532.                 yyerror("Region out of map range!");
  1533.             else if ($8 < 0 || $8 > max_y_map)
  1534.                 yyerror("Region out of map range!");
  1535.             current_region.x1 = $2;
  1536.             current_region.y1 = $4;
  1537.             current_region.x2 = $6;
  1538.             current_region.y2 = $8;
  1539.           }
  1540.         ;
  1541.  
  1542. %%
  1543.