home *** CD-ROM | disk | FTP | other *** search
- /* SCCS Id: @(#)mkmap.c 3.1 92/07/15 */
- /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */
- /* NetHack may be freely redistributed. See license for details. */
-
- #include "hack.h"
- #include "sp_lev.h"
-
- #define HEIGHT (ROWNO - 1)
- #define WIDTH (COLNO - 2)
-
- static void FDECL(init_map,(SCHAR_P));
- static void FDECL(init_fill,(SCHAR_P,SCHAR_P));
- static schar FDECL(get_map,(int,int,SCHAR_P));
- static void FDECL(pass_one,(SCHAR_P,SCHAR_P));
- static void FDECL(pass_two,(SCHAR_P,SCHAR_P));
- static void FDECL(pass_three,(SCHAR_P,SCHAR_P));
- static void NDECL(wallify_map);
- static void FDECL(join_map,(SCHAR_P,SCHAR_P));
- static void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P));
- void FDECL(mkmap, (lev_init *));
-
- char *new_locations;
- int min_rx, max_rx, min_ry, max_ry; /* rectangle bounds for regions */
- static int n_loc_filled;
-
- static void
- init_map(bg_typ)
- schar bg_typ;
- {
- register int i,j;
-
- for(i=1; i<COLNO; i++)
- for(j=0; j<ROWNO; j++)
- levl[i][j].typ = bg_typ;
- }
-
- static void
- init_fill(bg_typ, fg_typ)
- schar bg_typ, fg_typ;
- {
- register int i,j;
- long limit, count;
-
- limit = (WIDTH * HEIGHT * 2) / 5;
- count = 0;
- while(count < limit) {
- i = rn1(WIDTH-1, 2);
- j = rnd(HEIGHT-1);
- if (levl[i][j].typ == bg_typ) {
- levl[i][j].typ = fg_typ;
- count++;
- }
- }
- }
-
- static schar
- get_map(col,row, bg_typ)
- int col,row;
- schar bg_typ;
- {
- if (col <= 0 || row < 0 || col > WIDTH || row >= HEIGHT)
- return bg_typ;
- return levl[col][row].typ;
- }
-
- static int dirs[16] = {
- -1, -1 /**/, -1, 0 /**/, -1, 1 /**/,
- 0, -1 /**/, 0, 1 /**/,
- 1, -1 /**/, 1, 0 /**/, 1, 1};
-
- static void
- pass_one(bg_typ, fg_typ)
- schar bg_typ, fg_typ;
- {
- register int i,j;
- short count, dr;
-
- for(i=2; i<=WIDTH; i++)
- for(j=1; j<HEIGHT; j++) {
- for(count=0, dr=0; dr < 8; dr++)
- if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ)
- == fg_typ)
- count++;
-
- switch(count) {
- case 0 : /* death */
- case 1 :
- case 2:
- levl[i][j].typ = bg_typ;
- break;
- case 5:
- case 6:
- case 7:
- case 8:
- levl[i][j].typ = fg_typ;
- break;
- default:
- break;
- }
- }
- }
-
- #define new_loc(i,j) *(new_locations+ ((j)*(WIDTH+1)) + (i))
-
- static void
- pass_two(bg_typ, fg_typ)
- schar bg_typ, fg_typ;
- {
- register int i,j;
- short count, dr;
-
- for(i=2; i<=WIDTH; i++)
- for(j=1; j<HEIGHT; j++) {
- for(count=0, dr=0; dr < 8; dr++)
- if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ)
- == fg_typ)
- count++;
- if (count == 5)
- new_loc(i,j) = bg_typ;
- else
- new_loc(i,j) = get_map(i,j, bg_typ);
- }
-
- for(i=2; i<=WIDTH; i++)
- for(j=1; j<HEIGHT; j++)
- levl[i][j].typ = new_loc(i,j);
- }
-
- static void
- pass_three(bg_typ, fg_typ)
- schar bg_typ, fg_typ;
- {
- register int i,j;
- short count, dr;
-
- for(i=2; i<=WIDTH; i++)
- for(j=1; j<HEIGHT; j++) {
- for(count=0, dr=0; dr < 8; dr++)
- if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ)
- == fg_typ)
- count++;
- if (count < 3)
- new_loc(i,j) = bg_typ;
- else
- new_loc(i,j) = get_map(i,j, bg_typ);
- }
-
- for(i=2; i<=WIDTH; i++)
- for(j=1; j<HEIGHT; j++)
- levl[i][j].typ = new_loc(i,j);
- }
-
- /*
- * use a flooding algorithm to find all locations that should
- * have the same rm number as the current location.
- * if anyroom is TRUE, use IS_ROOM to check room membership instead of
- * exactly matching levl[sx][sy].typ and walls are included as well.
- */
- void
- flood_fill_rm(sx, sy, rmno, lit, anyroom)
- int sx;
- register int sy;
- register int rmno;
- boolean lit;
- boolean anyroom;
- {
- register int i;
- int nx;
- schar fg_typ = levl[sx][sy].typ;
-
- /* back up to find leftmost uninitialized location */
- while(sx > 0
- && (anyroom ? IS_ROOM(levl[sx][sy].typ) : levl[sx][sy].typ == fg_typ)
- && levl[sx][sy].roomno != rmno)
- sx--;
- sx++; /* compensate for extra decrement */
-
- /* assume sx,sy is valid */
- if(sx < min_rx) min_rx = sx;
- if(sy < min_ry) min_ry = sy;
-
- for(i=sx; i<=WIDTH && levl[i][sy].typ == fg_typ; i++) {
- levl[i][sy].roomno = rmno;
- levl[i][sy].lit = lit;
- if(anyroom) {
- /* add walls to room as well */
- register int ii,jj;
- for(ii= (i == sx ? i-1 : i); ii <= i+1; ii++)
- for(jj = sy-1; jj <= sy+1; jj++)
- if(isok(ii,jj) &&
- (IS_WALL(levl[ii][jj].typ) ||
- IS_DOOR(levl[ii][jj].typ))) {
- levl[ii][jj].edge = 1;
- if(lit) levl[ii][jj].lit = lit;
- if (levl[ii][jj].roomno != rmno)
- levl[ii][jj].roomno = SHARED;
- else
- levl[ii][jj].roomno = rmno;
- }
- }
- n_loc_filled++;
- }
- nx = i;
-
- if(isok(sx,sy-1))
- for(i=sx; i<nx; i++)
- if(levl[i][sy-1].typ == fg_typ) {
- if(levl[i][sy-1].roomno != rmno)
- flood_fill_rm(i,sy-1,rmno,lit,anyroom);
- } else {
- if((i>sx || isok(i-1,sy-1)) &&
- levl[i-1][sy-1].typ == fg_typ) {
- if(levl[i-1][sy-1].roomno != rmno)
- flood_fill_rm(i-1,sy-1,rmno,lit,anyroom);
- }
- if((i<nx-1 || isok(i+1,sy-1)) &&
- levl[i+1][sy-1].typ == fg_typ) {
- if(levl[i+1][sy-1].roomno != rmno)
- flood_fill_rm(i+1,sy-1,rmno,lit,anyroom);
- }
- }
- if(isok(sx,sy+1))
- for(i=sx; i<nx; i++)
- if(levl[i][sy+1].typ == fg_typ) {
- if(levl[i][sy+1].roomno != rmno)
- flood_fill_rm(i,sy+1,rmno,lit,anyroom);
- } else {
- if((i>sx || isok(i-1,sy+1)) &&
- levl[i-1][sy+1].typ == fg_typ) {
- if(levl[i-1][sy+1].roomno != rmno)
- flood_fill_rm(i-1,sy+1,rmno,lit,anyroom);
- }
- if((i<nx-1 || isok(i+1,sy+1)) &&
- levl[i+1][sy+1].typ == fg_typ) {
- if(levl[i+1][sy+1].roomno != rmno)
- flood_fill_rm(i+1,sy+1,rmno,lit,anyroom);
- }
- }
-
- if(nx > max_rx) max_rx = nx - 1; /* nx is just past valid region */
- if(sy > max_ry) max_ry = sy;
- }
-
- /*
- * If we have drawn a map without walls, this allows us to
- * auto-magically wallify it. Taken from lev_main.c.
- */
- static void
- wallify_map()
- {
-
- int x, y, xx, yy;
-
- for(x = 1; x < COLNO; x++)
- for(y = 0; y < ROWNO; y++)
- if(levl[x][y].typ == STONE) {
- for(yy = y - 1; yy <= y+1; yy++)
- for(xx = x - 1; xx <= x+1; xx++)
- if(isok(xx,yy) && levl[xx][yy].typ == ROOM) {
- if(yy != y) levl[x][y].typ = HWALL;
- else levl[x][y].typ = VWALL;
- }
- }
- }
-
- static void
- join_map(bg_typ, fg_typ)
- schar bg_typ, fg_typ;
- {
- register struct mkroom *croom, *croom2;
-
- register int i, j;
- int sx, sy;
- coord sm, em;
-
- /* first, use flood filling to find all of the regions that need joining */
- for(i=2; i<=WIDTH; i++)
- for(j=1; j<HEIGHT; j++) {
- if(levl[i][j].typ == fg_typ && levl[i][j].roomno == NO_ROOM) {
- min_rx = max_rx = i;
- min_ry = max_ry = j;
- n_loc_filled = 0;
- flood_fill_rm(i,j,nroom+ROOMOFFSET,FALSE,FALSE);
- if(n_loc_filled > 3) {
- add_room(min_rx, min_ry, max_rx, max_ry,
- FALSE, OROOM, TRUE);
- rooms[nroom-1].irregular = TRUE;
- if(nroom >= (MAXNROFROOMS*2))
- goto joinm;
- } else {
- /*
- * it's a tiny hole; erase it from the map to avoid
- * having the player end up here with no way out.
- */
- for(sx = min_rx; sx<=max_rx; sx++)
- for(sy = min_ry; sy<=max_ry; sy++)
- if(levl[sx][sy].roomno == nroom+ROOMOFFSET) {
- levl[sx][sy].typ = bg_typ;
- levl[sx][sy].roomno = NO_ROOM;
- }
- }
- }
- }
-
- joinm:
- /*
- * Ok, now we can actually join the regions with fg_typ's.
- * The rooms are already sorted due to the previous loop,
- * so don't call sort_rooms(), which can screw up the roomno's
- * validity in the levl structure.
- */
- for(croom = &rooms[0], croom2 = croom + 1; croom2 < &rooms[nroom]; ) {
- /* pick random starting and end locations for "corridor" */
- if(!somexy(croom, &sm) || !somexy(croom2, &em)) {
- /* ack! -- the level is going to be busted */
- /* arbitrarily pick centers of both rooms and hope for the best */
- impossible("No start/end room loc in join_map.");
- sm.x = croom->lx + ((croom->hx - croom->lx) / 2);
- sm.y = croom->ly + ((croom->hy - croom->ly) / 2);
- em.x = croom2->lx + ((croom2->hx - croom2->lx) / 2);
- em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2);
- }
-
- (void) dig_corridor(sm, em, FALSE, fg_typ, bg_typ);
-
- /* choose next region to join */
- /* only increment croom if croom and croom2 are non-overlapping */
- if(croom2->lx > croom->hx ||
- ((croom2->ly > croom->hy || croom2->hy < croom->ly) && rn2(3))) {
- croom = croom2;
- }
- croom2++; /* always increment the next room */
- }
- }
-
- static void
- finish_map(fg_typ, bg_typ, lit, walled)
- schar fg_typ, bg_typ;
- boolean lit, walled;
- {
- int i, j;
-
- if(walled) wallify_map();
-
- if(lit) {
- for(i=1; i<COLNO; i++)
- for(j=0; j<ROWNO; j++)
- if((!IS_ROCK(fg_typ) && levl[i][j].typ == fg_typ) ||
- (!IS_ROCK(bg_typ) && levl[i][j].typ == bg_typ) ||
- (walled && IS_WALL(levl[i][j].typ)))
- levl[i][j].lit = TRUE;
- for(i = 0; i < nroom; i++)
- rooms[i].rlit = 1;
- }
- }
-
- #define N_P1_ITER 1 /* tune map generation via this value */
- #define N_P2_ITER 1 /* tune map generation via this value */
- #define N_P3_ITER 2 /* tune map smoothing via this value */
-
- void
- mkmap(init_lev)
-
- lev_init *init_lev;
- {
- schar bg_typ = init_lev->bg,
- fg_typ = init_lev->fg;
- boolean smooth = init_lev->smoothed,
- join = init_lev->joined;
- xchar lit = init_lev->lit,
- walled = init_lev->walled;
- int i;
-
- if(lit < 0)
- lit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? 1 : 0;
-
- new_locations = (char *)alloc((WIDTH+1) * HEIGHT);
-
- init_map(bg_typ);
- init_fill(bg_typ, fg_typ);
-
- for(i = 0; i < N_P1_ITER; i++)
- pass_one(bg_typ, fg_typ);
-
- for(i = 0; i < N_P2_ITER; i++)
- pass_two(bg_typ, fg_typ);
-
- if(smooth)
- for(i = 0; i < N_P3_ITER; i++)
- pass_three(bg_typ, fg_typ);
-
- if(join)
- join_map(bg_typ, fg_typ);
-
- finish_map(fg_typ, bg_typ, (boolean)lit, (boolean)walled);
- /* a walled, joined level is cavernous, not mazelike -dlc */
- if (walled && join) {
- level.flags.is_maze_lev = FALSE;
- level.flags.is_cavernous_lev = TRUE;
- }
- free(new_locations);
- }
-