From: jwalz Date: Sat, 5 Jan 2002 21:06:00 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: MOVE2GIT~3627 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=17f3520f5247e66471ffccc5a94ce0f38007f4c8;p=nethack *** empty log message *** --- diff --git a/util/lev_comp.y b/util/lev_comp.y new file mode 100644 index 000000000..bdd747191 --- /dev/null +++ b/util/lev_comp.y @@ -0,0 +1,1678 @@ +%{ +/* SCCS Id: @(#)lev_yacc.c 3.3 2000/01/17 */ +/* Copyright (c) 1989 by Jean-Christophe Collet */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * This file contains the Level Compiler code + * It may handle special mazes & special room-levels + */ + +/* In case we're using bison in AIX. This definition must be + * placed before any other C-language construct in the file + * excluding comments and preprocessor directives (thanks IBM + * for this wonderful feature...). + * + * Note: some cpps barf on this 'undefined control' (#pragma). + * Addition of the leading space seems to prevent barfage for now, + * and AIX will still see the directive. + */ +#ifdef _AIX + #pragma alloca /* keep leading space! */ +#endif + +#include "hack.h" +#include "sp_lev.h" + +#define MAX_REGISTERS 10 +#define ERR (-1) +/* many types of things are put in chars for transference to NetHack. + * since some systems will use signed chars, limit everybody to the + * same number for portability. + */ +#define MAX_OF_TYPE 128 + +#define New(type) \ + (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type)) +#define NewTab(type, size) (type **) alloc(sizeof(type *) * size) +#define Free(ptr) free((genericptr_t)ptr) + +extern void FDECL(yyerror, (const char *)); +extern void FDECL(yywarning, (const char *)); +extern int NDECL(yylex); +int NDECL(yyparse); + +extern int FDECL(get_floor_type, (CHAR_P)); +extern int FDECL(get_room_type, (char *)); +extern int FDECL(get_trap_type, (char *)); +extern int FDECL(get_monster_id, (char *,CHAR_P)); +extern int FDECL(get_object_id, (char *,CHAR_P)); +extern boolean FDECL(check_monster_char, (CHAR_P)); +extern boolean FDECL(check_object_char, (CHAR_P)); +extern char FDECL(what_map_char, (CHAR_P)); +extern void FDECL(scan_map, (char *)); +extern void NDECL(wallify_map); +extern boolean NDECL(check_subrooms); +extern void FDECL(check_coord, (int,int,const char *)); +extern void NDECL(store_part); +extern void NDECL(store_room); +extern boolean FDECL(write_level_file, (char *,splev *,specialmaze *)); +extern void FDECL(free_rooms, (splev *)); + +static struct reg { + int x1, y1; + int x2, y2; +} current_region; + +static struct coord { + int x; + int y; +} current_coord, current_align; + +static struct size { + int height; + int width; +} current_size; + +char tmpmessage[256]; +digpos *tmppass[32]; +char *tmpmap[ROWNO]; + +digpos *tmpdig[MAX_OF_TYPE]; +region *tmpreg[MAX_OF_TYPE]; +lev_region *tmplreg[MAX_OF_TYPE]; +door *tmpdoor[MAX_OF_TYPE]; +drawbridge *tmpdb[MAX_OF_TYPE]; +walk *tmpwalk[MAX_OF_TYPE]; + +room_door *tmprdoor[MAX_OF_TYPE]; +trap *tmptrap[MAX_OF_TYPE]; +monster *tmpmonst[MAX_OF_TYPE]; +object *tmpobj[MAX_OF_TYPE]; +altar *tmpaltar[MAX_OF_TYPE]; +lad *tmplad[MAX_OF_TYPE]; +stair *tmpstair[MAX_OF_TYPE]; +gold *tmpgold[MAX_OF_TYPE]; +engraving *tmpengraving[MAX_OF_TYPE]; +fountain *tmpfountain[MAX_OF_TYPE]; +sink *tmpsink[MAX_OF_TYPE]; +pool *tmppool[MAX_OF_TYPE]; + +mazepart *tmppart[10]; +room *tmproom[MAXNROFROOMS*2]; +corridor *tmpcor[MAX_OF_TYPE]; + +static specialmaze maze; +static splev special_lev; +static lev_init init_lev; + +static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS]; +static struct coord plist[MAX_REGISTERS]; + +int n_olist = 0, n_mlist = 0, n_plist = 0; + +unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0; +unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0; +unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0; +unsigned int nfountain = 0, npool = 0, nsink = 0, npass = 0; + +static int lev_flags = 0; + +unsigned int max_x_map, max_y_map; + +static xchar in_room; + +extern int fatal_error; +extern int want_warnings; +extern const char *fname; + +%} + +%union +{ + int i; + char* map; + struct { + xchar room; + xchar wall; + xchar door; + } corpos; +} + + +%token CHAR INTEGER BOOLEAN PERCENT +%token MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID +%token OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID +%token MAZEWALK_ID WALLIFY_ID REGION_ID FILLING +%token RANDOM_OBJECTS_ID RANDOM_MONSTERS_ID RANDOM_PLACES_ID +%token ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID +%token PORTAL_ID TELEPRT_ID BRANCH_ID LEV CHANCE_ID +%token CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE +%token RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE +%token DIRECTION RANDOM_TYPE O_REGISTER M_REGISTER P_REGISTER A_REGISTER +%token ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN +%token SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS +%token MON_APPEARANCE +%token CONTAINED +%token ',' ':' '(' ')' '[' ']' +%token STRING MAP_ID +%type h_justif v_justif trap_name room_type door_state light_state +%type alignment altar_type a_register roomfill filling door_pos +%type door_wall walled secret amount chance +%type engraving_type flags flag_list prefilled lev_region lev_init +%type monster monster_c m_register object object_c o_register +%type string maze_def level_def m_name o_name +%type corr_spec +%start file + +%% +file : /* nothing */ + | levels + ; + +levels : level + | level levels + ; + +level : maze_level + | room_level + ; + +maze_level : maze_def flags lev_init messages regions + { + unsigned i; + + if (fatal_error > 0) { + (void) fprintf(stderr, + "%s : %d errors detected. No output created!\n", + fname, fatal_error); + } else { + maze.flags = $2; + (void) memcpy((genericptr_t)&(maze.init_lev), + (genericptr_t)&(init_lev), + sizeof(lev_init)); + maze.numpart = npart; + maze.parts = NewTab(mazepart, npart); + for(i=0;i 0) { + (void) fprintf(stderr, + "%s : %d errors detected. No output created!\n", + fname, fatal_error); + } else { + special_lev.flags = (long) $2; + (void) memcpy( + (genericptr_t)&(special_lev.init_lev), + (genericptr_t)&(init_lev), + sizeof(lev_init)); + special_lev.nroom = nrooms; + special_lev.rooms = NewTab(room, nrooms); + for(i=0; i 8) + yyerror("Level names limited to 8 characters."); + $$ = $3; + special_lev.nrmonst = special_lev.nrobjects = 0; + n_mlist = n_olist = 0; + } + ; + +lev_init : /* nothing */ + { + /* in case we're processing multiple files, + explicitly clear any stale settings */ + (void) memset((genericptr_t) &init_lev, 0, + sizeof init_lev); + init_lev.init_present = FALSE; + $$ = 0; + } + | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled + { + init_lev.init_present = TRUE; + init_lev.fg = what_map_char((char) $3); + if (init_lev.fg == INVALID_TYPE) + yyerror("Invalid foreground type."); + init_lev.bg = what_map_char((char) $5); + if (init_lev.bg == INVALID_TYPE) + yyerror("Invalid background type."); + init_lev.smoothed = $7; + init_lev.joined = $9; + init_lev.lit = $11; + init_lev.walled = $13; + $$ = 1; + } + ; + +walled : BOOLEAN + | RANDOM_TYPE + ; + +flags : /* nothing */ + { + $$ = 0; + } + | FLAGS_ID ':' flag_list + { + $$ = lev_flags; + lev_flags = 0; /* clear for next user */ + } + ; + +flag_list : FLAG_TYPE ',' flag_list + { + lev_flags |= $1; + } + | FLAG_TYPE + { + lev_flags |= $1; + } + ; + +messages : /* nothing */ + | message messages + ; + +message : MESSAGE_ID ':' STRING + { + int i, j; + + i = (int) strlen($3) + 1; + j = (int) strlen(tmpmessage); + if (i + j > 255) { + yyerror("Message string too long (>256 characters)"); + } else { + if (j) tmpmessage[j++] = '\n'; + (void) strncpy(tmpmessage+j, $3, i - 1); + tmpmessage[j + i - 1] = 0; + } + Free($3); + } + ; + +rreg_init : /* nothing */ + | rreg_init init_rreg + ; + +init_rreg : RANDOM_OBJECTS_ID ':' object_list + { + if(special_lev.nrobjects) { + yyerror("Object registers already initialized!"); + } else { + special_lev.nrobjects = n_olist; + special_lev.robjects = (char *) alloc(n_olist); + (void) memcpy((genericptr_t)special_lev.robjects, + (genericptr_t)olist, n_olist); + } + } + | RANDOM_MONSTERS_ID ':' monster_list + { + if(special_lev.nrmonst) { + yyerror("Monster registers already initialized!"); + } else { + special_lev.nrmonst = n_mlist; + special_lev.rmonst = (char *) alloc(n_mlist); + (void) memcpy((genericptr_t)special_lev.rmonst, + (genericptr_t)mlist, n_mlist); + } + } + ; + +rooms : /* Nothing - dummy room for use with INIT_MAP */ + { + tmproom[nrooms] = New(room); + tmproom[nrooms]->name = (char *) 0; + tmproom[nrooms]->parent = (char *) 0; + tmproom[nrooms]->rtype = 0; + tmproom[nrooms]->rlit = 0; + tmproom[nrooms]->xalign = ERR; + tmproom[nrooms]->yalign = ERR; + tmproom[nrooms]->x = 0; + tmproom[nrooms]->y = 0; + tmproom[nrooms]->w = 2; + tmproom[nrooms]->h = 2; + in_room = 1; + } + | roomlist + ; + +roomlist : aroom + | aroom roomlist + ; + +corridors_def : random_corridors + | corridors + ; + +random_corridors: RAND_CORRIDOR_ID + { + tmpcor[0] = New(corridor); + tmpcor[0]->src.room = -1; + ncorridor = 1; + } + ; + +corridors : /* nothing */ + | corridors corridor + ; + +corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec + { + tmpcor[ncorridor] = New(corridor); + tmpcor[ncorridor]->src.room = $3.room; + tmpcor[ncorridor]->src.wall = $3.wall; + tmpcor[ncorridor]->src.door = $3.door; + tmpcor[ncorridor]->dest.room = $5.room; + tmpcor[ncorridor]->dest.wall = $5.wall; + tmpcor[ncorridor]->dest.door = $5.door; + ncorridor++; + if (ncorridor >= MAX_OF_TYPE) { + yyerror("Too many corridors in level!"); + ncorridor--; + } + } + | CORRIDOR_ID ':' corr_spec ',' INTEGER + { + tmpcor[ncorridor] = New(corridor); + tmpcor[ncorridor]->src.room = $3.room; + tmpcor[ncorridor]->src.wall = $3.wall; + tmpcor[ncorridor]->src.door = $3.door; + tmpcor[ncorridor]->dest.room = -1; + tmpcor[ncorridor]->dest.wall = $5; + ncorridor++; + if (ncorridor >= MAX_OF_TYPE) { + yyerror("Too many corridors in level!"); + ncorridor--; + } + } + ; + +corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' + { + if ((unsigned) $2 >= nrooms) + yyerror("Wrong room number!"); + $$.room = $2; + $$.wall = $4; + $$.door = $6; + } + ; + +aroom : room_def room_details + { + store_room(); + } + | subroom_def room_details + { + store_room(); + } + ; + +subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill + { + tmproom[nrooms] = New(room); + tmproom[nrooms]->parent = $11; + tmproom[nrooms]->name = (char *) 0; + tmproom[nrooms]->rtype = $3; + tmproom[nrooms]->rlit = $5; + tmproom[nrooms]->filled = $12; + tmproom[nrooms]->xalign = ERR; + tmproom[nrooms]->yalign = ERR; + tmproom[nrooms]->x = current_coord.x; + tmproom[nrooms]->y = current_coord.y; + tmproom[nrooms]->w = current_size.width; + tmproom[nrooms]->h = current_size.height; + in_room = 1; + } + ; + +room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill + { + tmproom[nrooms] = New(room); + tmproom[nrooms]->name = (char *) 0; + tmproom[nrooms]->parent = (char *) 0; + tmproom[nrooms]->rtype = $3; + tmproom[nrooms]->rlit = $5; + tmproom[nrooms]->filled = $12; + tmproom[nrooms]->xalign = current_align.x; + tmproom[nrooms]->yalign = current_align.y; + tmproom[nrooms]->x = current_coord.x; + tmproom[nrooms]->y = current_coord.y; + tmproom[nrooms]->w = current_size.width; + tmproom[nrooms]->h = current_size.height; + in_room = 1; + } + ; + +roomfill : /* nothing */ + { + $$ = 1; + } + | ',' BOOLEAN + { + $$ = $2; + } + ; + +room_pos : '(' INTEGER ',' INTEGER ')' + { + if ( $2 < 1 || $2 > 5 || + $4 < 1 || $4 > 5 ) { + yyerror("Room position should be between 1 & 5!"); + } else { + current_coord.x = $2; + current_coord.y = $4; + } + } + | RANDOM_TYPE + { + current_coord.x = current_coord.y = ERR; + } + ; + +subroom_pos : '(' INTEGER ',' INTEGER ')' + { + if ( $2 < 0 || $4 < 0) { + yyerror("Invalid subroom position !"); + } else { + current_coord.x = $2; + current_coord.y = $4; + } + } + | RANDOM_TYPE + { + current_coord.x = current_coord.y = ERR; + } + ; + +room_align : '(' h_justif ',' v_justif ')' + { + current_align.x = $2; + current_align.y = $4; + } + | RANDOM_TYPE + { + current_align.x = current_align.y = ERR; + } + ; + +room_size : '(' INTEGER ',' INTEGER ')' + { + current_size.width = $2; + current_size.height = $4; + } + | RANDOM_TYPE + { + current_size.height = current_size.width = ERR; + } + ; + +room_details : /* nothing */ + | room_details room_detail + ; + +room_detail : room_name + | room_chance + | room_door + | monster_detail + | object_detail + | trap_detail + | altar_detail + | fountain_detail + | sink_detail + | pool_detail + | gold_detail + | engraving_detail + | stair_detail + ; + +room_name : NAME_ID ':' string + { + if (tmproom[nrooms]->name) + yyerror("This room already has a name!"); + else + tmproom[nrooms]->name = $3; + } + ; + +room_chance : CHANCE_ID ':' INTEGER + { + if (tmproom[nrooms]->chance) + yyerror("This room already assigned a chance!"); + else if (tmproom[nrooms]->rtype == OROOM) + yyerror("Only typed rooms can have a chance!"); + else if ($3 < 1 || $3 > 99) + yyerror("The chance is supposed to be percentile."); + else + tmproom[nrooms]->chance = $3; + } + ; + +room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos + { + /* ERR means random here */ + if ($7 == ERR && $9 != ERR) { + yyerror("If the door wall is random, so must be its pos!"); + } else { + tmprdoor[ndoor] = New(room_door); + tmprdoor[ndoor]->secret = $3; + tmprdoor[ndoor]->mask = $5; + tmprdoor[ndoor]->wall = $7; + tmprdoor[ndoor]->pos = $9; + ndoor++; + if (ndoor >= MAX_OF_TYPE) { + yyerror("Too many doors in room!"); + ndoor--; + } + } + } + ; + +secret : BOOLEAN + | RANDOM_TYPE + ; + +door_wall : DIRECTION + | RANDOM_TYPE + ; + +door_pos : INTEGER + | RANDOM_TYPE + ; + +maze_def : MAZE_ID ':' string ',' filling + { + maze.filling = (schar) $5; + if (index($3, '.')) + yyerror("Invalid dot ('.') in level name."); + if ((int) strlen($3) > 8) + yyerror("Level names limited to 8 characters."); + $$ = $3; + in_room = 0; + n_plist = n_mlist = n_olist = 0; + } + ; + +filling : CHAR + { + $$ = get_floor_type((char)$1); + } + | RANDOM_TYPE + { + $$ = -1; + } + ; + +regions : aregion + | aregion regions + ; + +aregion : map_definition reg_init map_details + { + store_part(); + } + ; + +map_definition : NOMAP_ID + { + tmppart[npart] = New(mazepart); + tmppart[npart]->halign = 1; + tmppart[npart]->valign = 1; + tmppart[npart]->nrobjects = 0; + tmppart[npart]->nloc = 0; + tmppart[npart]->nrmonst = 0; + tmppart[npart]->xsize = 1; + tmppart[npart]->ysize = 1; + tmppart[npart]->map = (char **) alloc(sizeof(char *)); + tmppart[npart]->map[0] = (char *) alloc(1); + tmppart[npart]->map[0][0] = STONE; + max_x_map = COLNO-1; + max_y_map = ROWNO; + } + | map_geometry MAP_ID + { + tmppart[npart] = New(mazepart); + tmppart[npart]->halign = $1 % 10; + tmppart[npart]->valign = $1 / 10; + tmppart[npart]->nrobjects = 0; + tmppart[npart]->nloc = 0; + tmppart[npart]->nrmonst = 0; + scan_map($2); + Free($2); + } + ; + +map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif + { + $$ = $3 + ($5 * 10); + } + ; + +h_justif : LEFT_OR_RIGHT + | CENTER + ; + +v_justif : TOP_OR_BOT + | CENTER + ; + +reg_init : /* nothing */ + | reg_init init_reg + ; + +init_reg : RANDOM_OBJECTS_ID ':' object_list + { + if (tmppart[npart]->nrobjects) { + yyerror("Object registers already initialized!"); + } else { + tmppart[npart]->robjects = (char *)alloc(n_olist); + (void) memcpy((genericptr_t)tmppart[npart]->robjects, + (genericptr_t)olist, n_olist); + tmppart[npart]->nrobjects = n_olist; + } + } + | RANDOM_PLACES_ID ':' place_list + { + if (tmppart[npart]->nloc) { + yyerror("Location registers already initialized!"); + } else { + register int i; + tmppart[npart]->rloc_x = (char *) alloc(n_plist); + tmppart[npart]->rloc_y = (char *) alloc(n_plist); + for(i=0;irloc_x[i] = plist[i].x; + tmppart[npart]->rloc_y[i] = plist[i].y; + } + tmppart[npart]->nloc = n_plist; + } + } + | RANDOM_MONSTERS_ID ':' monster_list + { + if (tmppart[npart]->nrmonst) { + yyerror("Monster registers already initialized!"); + } else { + tmppart[npart]->rmonst = (char *) alloc(n_mlist); + (void) memcpy((genericptr_t)tmppart[npart]->rmonst, + (genericptr_t)mlist, n_mlist); + tmppart[npart]->nrmonst = n_mlist; + } + } + ; + +object_list : object + { + if (n_olist < MAX_REGISTERS) + olist[n_olist++] = $1; + else + yyerror("Object list too long!"); + } + | object ',' object_list + { + if (n_olist < MAX_REGISTERS) + olist[n_olist++] = $1; + else + yyerror("Object list too long!"); + } + ; + +monster_list : monster + { + if (n_mlist < MAX_REGISTERS) + mlist[n_mlist++] = $1; + else + yyerror("Monster list too long!"); + } + | monster ',' monster_list + { + if (n_mlist < MAX_REGISTERS) + mlist[n_mlist++] = $1; + else + yyerror("Monster list too long!"); + } + ; + +place_list : place + { + if (n_plist < MAX_REGISTERS) + plist[n_plist++] = current_coord; + else + yyerror("Location list too long!"); + } + | place + { + if (n_plist < MAX_REGISTERS) + plist[n_plist++] = current_coord; + else + yyerror("Location list too long!"); + } + ',' place_list + ; + +map_details : /* nothing */ + | map_details map_detail + ; + +map_detail : monster_detail + | object_detail + | door_detail + | trap_detail + | drawbridge_detail + | region_detail + | stair_region + | portal_region + | teleprt_region + | branch_region + | altar_detail + | fountain_detail + | mazewalk_detail + | wallify_detail + | ladder_detail + | stair_detail + | gold_detail + | engraving_detail + | diggable_detail + | passwall_detail + ; + +monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate + { + tmpmonst[nmons] = New(monster); + tmpmonst[nmons]->x = current_coord.x; + tmpmonst[nmons]->y = current_coord.y; + tmpmonst[nmons]->class = $4; + tmpmonst[nmons]->peaceful = -1; /* no override */ + tmpmonst[nmons]->asleep = -1; + tmpmonst[nmons]->align = - MAX_REGISTERS - 2; + tmpmonst[nmons]->name.str = 0; + tmpmonst[nmons]->appear = 0; + tmpmonst[nmons]->appear_as.str = 0; + tmpmonst[nmons]->chance = $2; + tmpmonst[nmons]->id = NON_PM; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Monster"); + if ($6) { + int token = get_monster_id($6, (char) $4); + if (token == ERR) + yywarning( + "Invalid monster name! Making random monster."); + else + tmpmonst[nmons]->id = token; + Free($6); + } + } + monster_infos + { + if (++nmons >= MAX_OF_TYPE) { + yyerror("Too many monsters in room or mazepart!"); + nmons--; + } + } + ; + +monster_infos : /* nothing */ + | monster_infos monster_info + ; + +monster_info : ',' string + { + tmpmonst[nmons]->name.str = $2; + } + | ',' MON_ATTITUDE + { + tmpmonst[nmons]->peaceful = $2; + } + | ',' MON_ALERTNESS + { + tmpmonst[nmons]->asleep = $2; + } + | ',' alignment + { + tmpmonst[nmons]->align = $2; + } + | ',' MON_APPEARANCE string + { + tmpmonst[nmons]->appear = $2; + tmpmonst[nmons]->appear_as.str = $3; + } + ; + +object_detail : OBJECT_ID object_desc + { + } + | COBJECT_ID object_desc + { + /* 1: is contents of next object with 2 */ + /* 2: is a container */ + /* 0: neither */ + tmpobj[nobj-1]->containment = 2; + } + ; + +object_desc : chance ':' object_c ',' o_name + { + tmpobj[nobj] = New(object); + tmpobj[nobj]->class = $3; + tmpobj[nobj]->corpsenm = NON_PM; + tmpobj[nobj]->curse_state = -1; + tmpobj[nobj]->name.str = 0; + tmpobj[nobj]->chance = $1; + tmpobj[nobj]->id = -1; + if ($5) { + int token = get_object_id($5, $3); + if (token == ERR) + yywarning( + "Illegal object name! Making random object."); + else + tmpobj[nobj]->id = token; + Free($5); + } + } + ',' object_where object_infos + { + if (++nobj >= MAX_OF_TYPE) { + yyerror("Too many objects in room or mazepart!"); + nobj--; + } + } + ; + +object_where : coordinate + { + tmpobj[nobj]->containment = 0; + tmpobj[nobj]->x = current_coord.x; + tmpobj[nobj]->y = current_coord.y; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Object"); + } + | CONTAINED + { + tmpobj[nobj]->containment = 1; + /* random coordinate, will be overridden anyway */ + tmpobj[nobj]->x = -MAX_REGISTERS-1; + tmpobj[nobj]->y = -MAX_REGISTERS-1; + } + ; + +object_infos : /* nothing */ + { + tmpobj[nobj]->spe = -127; + /* Note below: we're trying to make as many of these optional as + * possible. We clearly can't make curse_state, enchantment, and + * monster_id _all_ optional, since ",random" would be ambiguous. + * We can't even just make enchantment mandatory, since if we do that + * alone, ",random" requires too much lookahead to parse. + */ + } + | ',' curse_state ',' monster_id ',' enchantment optional_name + { + } + | ',' curse_state ',' enchantment optional_name + { + } + | ',' monster_id ',' enchantment optional_name + { + } + ; + +curse_state : RANDOM_TYPE + { + tmpobj[nobj]->curse_state = -1; + } + | CURSE_TYPE + { + tmpobj[nobj]->curse_state = $1; + } + ; + +monster_id : STRING + { + int token = get_monster_id($1, (char)0); + if (token == ERR) /* "random" */ + tmpobj[nobj]->corpsenm = NON_PM - 1; + else + tmpobj[nobj]->corpsenm = token; + Free($1); + } + ; + +enchantment : RANDOM_TYPE + { + tmpobj[nobj]->spe = -127; + } + | INTEGER + { + tmpobj[nobj]->spe = $1; + } + ; + +optional_name : /* nothing */ + | ',' NONE + { + } + | ',' STRING + { + tmpobj[nobj]->name.str = $2; + } + ; + +door_detail : DOOR_ID ':' door_state ',' coordinate + { + tmpdoor[ndoor] = New(door); + tmpdoor[ndoor]->x = current_coord.x; + tmpdoor[ndoor]->y = current_coord.y; + tmpdoor[ndoor]->mask = $3; + if(current_coord.x >= 0 && current_coord.y >= 0 && + tmpmap[current_coord.y][current_coord.x] != DOOR && + tmpmap[current_coord.y][current_coord.x] != SDOOR) + yyerror("Door decl doesn't match the map"); + ndoor++; + if (ndoor >= MAX_OF_TYPE) { + yyerror("Too many doors in mazepart!"); + ndoor--; + } + } + ; + +trap_detail : TRAP_ID chance ':' trap_name ',' coordinate + { + tmptrap[ntrap] = New(trap); + tmptrap[ntrap]->x = current_coord.x; + tmptrap[ntrap]->y = current_coord.y; + tmptrap[ntrap]->type = $4; + tmptrap[ntrap]->chance = $2; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Trap"); + if (++ntrap >= MAX_OF_TYPE) { + yyerror("Too many traps in room or mazepart!"); + ntrap--; + } + } + ; + +drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state + { + int x, y, dir; + + tmpdb[ndb] = New(drawbridge); + x = tmpdb[ndb]->x = current_coord.x; + y = tmpdb[ndb]->y = current_coord.y; + /* convert dir from a DIRECTION to a DB_DIR */ + dir = $5; + switch(dir) { + case W_NORTH: dir = DB_NORTH; y--; break; + case W_SOUTH: dir = DB_SOUTH; y++; break; + case W_EAST: dir = DB_EAST; x++; break; + case W_WEST: dir = DB_WEST; x--; break; + default: + yyerror("Invalid drawbridge direction"); + break; + } + tmpdb[ndb]->dir = dir; + if (current_coord.x >= 0 && current_coord.y >= 0 && + !IS_WALL(tmpmap[y][x])) { + char ebuf[60]; + Sprintf(ebuf, + "Wall needed for drawbridge (%02d, %02d)", + current_coord.x, current_coord.y); + yyerror(ebuf); + } + + if ( $7 == D_ISOPEN ) + tmpdb[ndb]->db_open = 1; + else if ( $7 == D_CLOSED ) + tmpdb[ndb]->db_open = 0; + else + yyerror("A drawbridge can only be open or closed!"); + ndb++; + if (ndb >= MAX_OF_TYPE) { + yyerror("Too many drawbridges in mazepart!"); + ndb--; + } + } + ; + +mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION + { + tmpwalk[nwalk] = New(walk); + tmpwalk[nwalk]->x = current_coord.x; + tmpwalk[nwalk]->y = current_coord.y; + tmpwalk[nwalk]->dir = $5; + nwalk++; + if (nwalk >= MAX_OF_TYPE) { + yyerror("Too many mazewalks in mazepart!"); + nwalk--; + } + } + ; + +wallify_detail : WALLIFY_ID + { + wallify_map(); + } + ; + +ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN + { + tmplad[nlad] = New(lad); + tmplad[nlad]->x = current_coord.x; + tmplad[nlad]->y = current_coord.y; + tmplad[nlad]->up = $5; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Ladder"); + nlad++; + if (nlad >= MAX_OF_TYPE) { + yyerror("Too many ladders in mazepart!"); + nlad--; + } + } + ; + +stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN + { + tmpstair[nstair] = New(stair); + tmpstair[nstair]->x = current_coord.x; + tmpstair[nstair]->y = current_coord.y; + tmpstair[nstair]->up = $5; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Stairway"); + nstair++; + if (nstair >= MAX_OF_TYPE) { + yyerror("Too many stairs in room or mazepart!"); + nstair--; + } + } + ; + +stair_region : STAIR_ID ':' lev_region + { + tmplreg[nlreg] = New(lev_region); + tmplreg[nlreg]->in_islev = $3; + tmplreg[nlreg]->inarea.x1 = current_region.x1; + tmplreg[nlreg]->inarea.y1 = current_region.y1; + tmplreg[nlreg]->inarea.x2 = current_region.x2; + tmplreg[nlreg]->inarea.y2 = current_region.y2; + } + ',' lev_region ',' UP_OR_DOWN + { + tmplreg[nlreg]->del_islev = $6; + tmplreg[nlreg]->delarea.x1 = current_region.x1; + tmplreg[nlreg]->delarea.y1 = current_region.y1; + tmplreg[nlreg]->delarea.x2 = current_region.x2; + tmplreg[nlreg]->delarea.y2 = current_region.y2; + if($8) + tmplreg[nlreg]->rtype = LR_UPSTAIR; + else + tmplreg[nlreg]->rtype = LR_DOWNSTAIR; + tmplreg[nlreg]->rname.str = 0; + nlreg++; + if (nlreg >= MAX_OF_TYPE) { + yyerror("Too many levregions in mazepart!"); + nlreg--; + } + } + ; + +portal_region : PORTAL_ID ':' lev_region + { + tmplreg[nlreg] = New(lev_region); + tmplreg[nlreg]->in_islev = $3; + tmplreg[nlreg]->inarea.x1 = current_region.x1; + tmplreg[nlreg]->inarea.y1 = current_region.y1; + tmplreg[nlreg]->inarea.x2 = current_region.x2; + tmplreg[nlreg]->inarea.y2 = current_region.y2; + } + ',' lev_region ',' string + { + tmplreg[nlreg]->del_islev = $6; + tmplreg[nlreg]->delarea.x1 = current_region.x1; + tmplreg[nlreg]->delarea.y1 = current_region.y1; + tmplreg[nlreg]->delarea.x2 = current_region.x2; + tmplreg[nlreg]->delarea.y2 = current_region.y2; + tmplreg[nlreg]->rtype = LR_PORTAL; + tmplreg[nlreg]->rname.str = $8; + nlreg++; + if (nlreg >= MAX_OF_TYPE) { + yyerror("Too many levregions in mazepart!"); + nlreg--; + } + } + ; + +teleprt_region : TELEPRT_ID ':' lev_region + { + tmplreg[nlreg] = New(lev_region); + tmplreg[nlreg]->in_islev = $3; + tmplreg[nlreg]->inarea.x1 = current_region.x1; + tmplreg[nlreg]->inarea.y1 = current_region.y1; + tmplreg[nlreg]->inarea.x2 = current_region.x2; + tmplreg[nlreg]->inarea.y2 = current_region.y2; + } + ',' lev_region + { + tmplreg[nlreg]->del_islev = $6; + tmplreg[nlreg]->delarea.x1 = current_region.x1; + tmplreg[nlreg]->delarea.y1 = current_region.y1; + tmplreg[nlreg]->delarea.x2 = current_region.x2; + tmplreg[nlreg]->delarea.y2 = current_region.y2; + } + teleprt_detail + { + switch($8) { + case -1: tmplreg[nlreg]->rtype = LR_TELE; break; + case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break; + case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break; + } + tmplreg[nlreg]->rname.str = 0; + nlreg++; + if (nlreg >= MAX_OF_TYPE) { + yyerror("Too many levregions in mazepart!"); + nlreg--; + } + } + ; + +branch_region : BRANCH_ID ':' lev_region + { + tmplreg[nlreg] = New(lev_region); + tmplreg[nlreg]->in_islev = $3; + tmplreg[nlreg]->inarea.x1 = current_region.x1; + tmplreg[nlreg]->inarea.y1 = current_region.y1; + tmplreg[nlreg]->inarea.x2 = current_region.x2; + tmplreg[nlreg]->inarea.y2 = current_region.y2; + } + ',' lev_region + { + tmplreg[nlreg]->del_islev = $6; + tmplreg[nlreg]->delarea.x1 = current_region.x1; + tmplreg[nlreg]->delarea.y1 = current_region.y1; + tmplreg[nlreg]->delarea.x2 = current_region.x2; + tmplreg[nlreg]->delarea.y2 = current_region.y2; + tmplreg[nlreg]->rtype = LR_BRANCH; + tmplreg[nlreg]->rname.str = 0; + nlreg++; + if (nlreg >= MAX_OF_TYPE) { + yyerror("Too many levregions in mazepart!"); + nlreg--; + } + } + ; + +teleprt_detail : /* empty */ + { + $$ = -1; + } + | ',' UP_OR_DOWN + { + $$ = $2; + } + ; + +lev_region : region + { + $$ = 0; + } + | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' + { +/* This series of if statements is a hack for MSC 5.1. It seems that its + tiny little brain cannot compile if these are all one big if statement. */ + if ($3 <= 0 || $3 >= COLNO) + yyerror("Region out of level range!"); + else if ($5 < 0 || $5 >= ROWNO) + yyerror("Region out of level range!"); + else if ($7 <= 0 || $7 >= COLNO) + yyerror("Region out of level range!"); + else if ($9 < 0 || $9 >= ROWNO) + yyerror("Region out of level range!"); + current_region.x1 = $3; + current_region.y1 = $5; + current_region.x2 = $7; + current_region.y2 = $9; + $$ = 1; + } + ; + +fountain_detail : FOUNTAIN_ID ':' coordinate + { + tmpfountain[nfountain] = New(fountain); + tmpfountain[nfountain]->x = current_coord.x; + tmpfountain[nfountain]->y = current_coord.y; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Fountain"); + nfountain++; + if (nfountain >= MAX_OF_TYPE) { + yyerror("Too many fountains in room or mazepart!"); + nfountain--; + } + } + ; + +sink_detail : SINK_ID ':' coordinate + { + tmpsink[nsink] = New(sink); + tmpsink[nsink]->x = current_coord.x; + tmpsink[nsink]->y = current_coord.y; + nsink++; + if (nsink >= MAX_OF_TYPE) { + yyerror("Too many sinks in room!"); + nsink--; + } + } + ; + +pool_detail : POOL_ID ':' coordinate + { + tmppool[npool] = New(pool); + tmppool[npool]->x = current_coord.x; + tmppool[npool]->y = current_coord.y; + npool++; + if (npool >= MAX_OF_TYPE) { + yyerror("Too many pools in room!"); + npool--; + } + } + ; + +diggable_detail : NON_DIGGABLE_ID ':' region + { + tmpdig[ndig] = New(digpos); + tmpdig[ndig]->x1 = current_region.x1; + tmpdig[ndig]->y1 = current_region.y1; + tmpdig[ndig]->x2 = current_region.x2; + tmpdig[ndig]->y2 = current_region.y2; + ndig++; + if (ndig >= MAX_OF_TYPE) { + yyerror("Too many diggables in mazepart!"); + ndig--; + } + } + ; + +passwall_detail : NON_PASSWALL_ID ':' region + { + tmppass[npass] = New(digpos); + tmppass[npass]->x1 = current_region.x1; + tmppass[npass]->y1 = current_region.y1; + tmppass[npass]->x2 = current_region.x2; + tmppass[npass]->y2 = current_region.y2; + npass++; + if (npass >= 32) { + yyerror("Too many passwalls in mazepart!"); + npass--; + } + } + ; + +region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled + { + tmpreg[nreg] = New(region); + tmpreg[nreg]->x1 = current_region.x1; + tmpreg[nreg]->y1 = current_region.y1; + tmpreg[nreg]->x2 = current_region.x2; + tmpreg[nreg]->y2 = current_region.y2; + tmpreg[nreg]->rlit = $5; + tmpreg[nreg]->rtype = $7; + if($8 & 1) tmpreg[nreg]->rtype += MAXRTYPE+1; + tmpreg[nreg]->rirreg = (($8 & 2) != 0); + if(current_region.x1 > current_region.x2 || + current_region.y1 > current_region.y2) + yyerror("Region start > end!"); + if(tmpreg[nreg]->rtype == VAULT && + (tmpreg[nreg]->rirreg || + (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) || + (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1))) + yyerror("Vaults must be exactly 2x2!"); + if(want_warnings && !tmpreg[nreg]->rirreg && + current_region.x1 > 0 && current_region.y1 > 0 && + current_region.x2 < (int)max_x_map && + current_region.y2 < (int)max_y_map) { + /* check for walls in the room */ + char ebuf[60]; + register int x, y, nrock = 0; + + for(y=current_region.y1; y<=current_region.y2; y++) + for(x=current_region.x1; + x<=current_region.x2; x++) + if(IS_ROCK(tmpmap[y][x]) || + IS_DOOR(tmpmap[y][x])) nrock++; + if(nrock) { + Sprintf(ebuf, + "Rock in room (%02d,%02d,%02d,%02d)?!", + current_region.x1, current_region.y1, + current_region.x2, current_region.y2); + yywarning(ebuf); + } + if ( + !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) || + !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) || + !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) || + !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) { + Sprintf(ebuf, + "NonRock edge in room (%02d,%02d,%02d,%02d)?!", + current_region.x1, current_region.y1, + current_region.x2, current_region.y2); + yywarning(ebuf); + } + } else if(tmpreg[nreg]->rirreg && + !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) { + char ebuf[60]; + Sprintf(ebuf, + "Rock in irregular room (%02d,%02d)?!", + current_region.x1, current_region.y1); + yyerror(ebuf); + } + nreg++; + if (nreg >= MAX_OF_TYPE) { + yyerror("Too many regions in mazepart!"); + nreg--; + } + } + ; + +altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type + { + tmpaltar[naltar] = New(altar); + tmpaltar[naltar]->x = current_coord.x; + tmpaltar[naltar]->y = current_coord.y; + tmpaltar[naltar]->align = $5; + tmpaltar[naltar]->shrine = $7; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Altar"); + naltar++; + if (naltar >= MAX_OF_TYPE) { + yyerror("Too many altars in room or mazepart!"); + naltar--; + } + } + ; + +gold_detail : GOLD_ID ':' amount ',' coordinate + { + tmpgold[ngold] = New(gold); + tmpgold[ngold]->x = current_coord.x; + tmpgold[ngold]->y = current_coord.y; + tmpgold[ngold]->amount = $3; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Gold"); + ngold++; + if (ngold >= MAX_OF_TYPE) { + yyerror("Too many golds in room or mazepart!"); + ngold--; + } + } + ; + +engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string + { + tmpengraving[nengraving] = New(engraving); + tmpengraving[nengraving]->x = current_coord.x; + tmpengraving[nengraving]->y = current_coord.y; + tmpengraving[nengraving]->engr.str = $7; + tmpengraving[nengraving]->etype = $5; + if (!in_room) + check_coord(current_coord.x, current_coord.y, + "Engraving"); + nengraving++; + if (nengraving >= MAX_OF_TYPE) { + yyerror("Too many engravings in room or mazepart!"); + nengraving--; + } + } + ; + +monster_c : monster + | RANDOM_TYPE + { + $$ = - MAX_REGISTERS - 1; + } + | m_register + ; + +object_c : object + | RANDOM_TYPE + { + $$ = - MAX_REGISTERS - 1; + } + | o_register + ; + +m_name : string + | RANDOM_TYPE + { + $$ = (char *) 0; + } + ; + +o_name : string + | RANDOM_TYPE + { + $$ = (char *) 0; + } + ; + +trap_name : string + { + int token = get_trap_type($1); + if (token == ERR) + yyerror("Unknown trap type!"); + $$ = token; + Free($1); + } + | RANDOM_TYPE + ; + +room_type : string + { + int token = get_room_type($1); + if (token == ERR) { + yywarning("Unknown room type! Making ordinary room..."); + $$ = OROOM; + } else + $$ = token; + Free($1); + } + | RANDOM_TYPE + ; + +prefilled : /* empty */ + { + $$ = 0; + } + | ',' FILLING + { + $$ = $2; + } + | ',' FILLING ',' BOOLEAN + { + $$ = $2 + ($4 << 1); + } + ; + +coordinate : coord + | p_register + | RANDOM_TYPE + { + current_coord.x = current_coord.y = -MAX_REGISTERS-1; + } + ; + +door_state : DOOR_STATE + | RANDOM_TYPE + ; + +light_state : LIGHT_STATE + | RANDOM_TYPE + ; + +alignment : ALIGNMENT + | a_register + | RANDOM_TYPE + { + $$ = - MAX_REGISTERS - 1; + } + ; + +altar_type : ALTAR_TYPE + | RANDOM_TYPE + ; + +p_register : P_REGISTER '[' INTEGER ']' + { + if ( $3 >= MAX_REGISTERS ) + yyerror("Register Index overflow!"); + else + current_coord.x = current_coord.y = - $3 - 1; + } + ; + +o_register : O_REGISTER '[' INTEGER ']' + { + if ( $3 >= MAX_REGISTERS ) + yyerror("Register Index overflow!"); + else + $$ = - $3 - 1; + } + ; + +m_register : M_REGISTER '[' INTEGER ']' + { + if ( $3 >= MAX_REGISTERS ) + yyerror("Register Index overflow!"); + else + $$ = - $3 - 1; + } + ; + +a_register : A_REGISTER '[' INTEGER ']' + { + if ( $3 >= 3 ) + yyerror("Register Index overflow!"); + else + $$ = - $3 - 1; + } + ; + +place : coord + ; + +monster : CHAR + { + if (check_monster_char((char) $1)) + $$ = $1 ; + else { + yyerror("Unknown monster class!"); + $$ = ERR; + } + } + ; + +object : CHAR + { + char c = $1; + if (check_object_char(c)) + $$ = c; + else { + yyerror("Unknown char class!"); + $$ = ERR; + } + } + ; + +string : STRING + ; + +amount : INTEGER + | RANDOM_TYPE + ; + +chance : /* empty */ + { + $$ = 100; /* default is 100% */ + } + | PERCENT + { + if ($1 <= 0 || $1 > 100) + yyerror("Expected percentile chance."); + $$ = $1; + } + ; + +engraving_type : ENGRAVING_TYPE + | RANDOM_TYPE + ; + +coord : '(' INTEGER ',' INTEGER ')' + { + if (!in_room && !init_lev.init_present && + ($2 < 0 || $2 > (int)max_x_map || + $4 < 0 || $4 > (int)max_y_map)) + yyerror("Coordinates out of map range!"); + current_coord.x = $2; + current_coord.y = $4; + } + ; + +region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' + { +/* This series of if statements is a hack for MSC 5.1. It seems that its + tiny little brain cannot compile if these are all one big if statement. */ + if ($2 < 0 || $2 > (int)max_x_map) + yyerror("Region out of map range!"); + else if ($4 < 0 || $4 > (int)max_y_map) + yyerror("Region out of map range!"); + else if ($6 < 0 || $6 > (int)max_x_map) + yyerror("Region out of map range!"); + else if ($8 < 0 || $8 > (int)max_y_map) + yyerror("Region out of map range!"); + current_region.x1 = $2; + current_region.y1 = $4; + current_region.x2 = $6; + current_region.y2 = $8; + } + ; + +%% + +/*lev_comp.y*/