1 | /* SCCS Id: @(#)mkmap.c 3.3 96/05/23 */ 2 | /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | #include "hack.h" 6 | #include "sp_lev.h" 7 | 8 | #define HEIGHT (ROWNO - 1) 9 | #define WIDTH (COLNO - 2) 10 | 11 | STATIC_DCL void FDECL(init_map,(SCHAR_P)); 12 | STATIC_DCL void FDECL(init_fill,(SCHAR_P,SCHAR_P)); 13 | STATIC_DCL schar FDECL(get_map,(int,int,SCHAR_P)); 14 | STATIC_DCL void FDECL(pass_one,(SCHAR_P,SCHAR_P)); 15 | STATIC_DCL void FDECL(pass_two,(SCHAR_P,SCHAR_P)); 16 | STATIC_DCL void FDECL(pass_three,(SCHAR_P,SCHAR_P)); 17 | STATIC_DCL void NDECL(wallify_map); 18 | STATIC_DCL void FDECL(join_map,(SCHAR_P,SCHAR_P)); 19 | STATIC_DCL void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P)); 20 | void FDECL(mkmap, (lev_init *)); 21 | 22 | char *new_locations; 23 | int min_rx, max_rx, min_ry, max_ry; /* rectangle bounds for regions */ 24 | static int n_loc_filled; 25 | 26 | STATIC_OVL void 27 | init_map(bg_typ) 28 | schar bg_typ; 29 | { 30 | register int i,j; 31 | 32 | for(i=1; i<COLNO; i++) 33 | for(j=0; j<ROWNO; j++) 34 | levl[i][j].typ = bg_typ; 35 | } 36 | 37 | STATIC_OVL void 38 | init_fill(bg_typ, fg_typ) 39 | schar bg_typ, fg_typ; 40 | { 41 | register int i,j; 42 | long limit, count; 43 | 44 | limit = (WIDTH * HEIGHT * 2) / 5; 45 | count = 0; 46 | while(count < limit) { 47 | i = rn1(WIDTH-1, 2); 48 | j = rnd(HEIGHT-1); 49 | if (levl[i][j].typ == bg_typ) { 50 | levl[i][j].typ = fg_typ; 51 | count++; 52 | } 53 | } 54 | } 55 | 56 | STATIC_OVL schar 57 | get_map(col,row, bg_typ) 58 | int col,row; 59 | schar bg_typ; 60 | { 61 | if (col <= 0 || row < 0 || col > WIDTH || row >= HEIGHT) 62 | return bg_typ; 63 | return levl[col][row].typ; 64 | } 65 | 66 | static int dirs[16] = { 67 | -1, -1 /**/, -1, 0 /**/, -1, 1 /**/, 68 | 0, -1 /**/, 0, 1 /**/, 69 | 1, -1 /**/, 1, 0 /**/, 1, 1}; 70 | 71 | STATIC_OVL void 72 | pass_one(bg_typ, fg_typ) 73 | schar bg_typ, fg_typ; 74 | { 75 | register int i,j; 76 | short count, dr; 77 | 78 | for(i=2; i<=WIDTH; i++) 79 | for(j=1; j<HEIGHT; j++) { 80 | for(count=0, dr=0; dr < 8; dr++) 81 | if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ) 82 | == fg_typ) 83 | count++; 84 | 85 | switch(count) { 86 | case 0 : /* death */ 87 | case 1 : 88 | case 2: 89 | levl[i][j].typ = bg_typ; 90 | break; 91 | case 5: 92 | case 6: 93 | case 7: 94 | case 8: 95 | levl[i][j].typ = fg_typ; 96 | break; 97 | default: 98 | break; 99 | } 100 | } 101 | } 102 | 103 | #define new_loc(i,j) *(new_locations+ ((j)*(WIDTH+1)) + (i)) 104 | 105 | STATIC_OVL void 106 | pass_two(bg_typ, fg_typ) 107 | schar bg_typ, fg_typ; 108 | { 109 | register int i,j; 110 | short count, dr; 111 | 112 | for(i=2; i<=WIDTH; i++) 113 | for(j=1; j<HEIGHT; j++) { 114 | for(count=0, dr=0; dr < 8; dr++) 115 | if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ) 116 | == fg_typ) 117 | count++; 118 | if (count == 5) 119 | new_loc(i,j) = bg_typ; 120 | else 121 | new_loc(i,j) = get_map(i,j, bg_typ); 122 | } 123 | 124 | for(i=2; i<=WIDTH; i++) 125 | for(j=1; j<HEIGHT; j++) 126 | levl[i][j].typ = new_loc(i,j); 127 | } 128 | 129 | STATIC_OVL void 130 | pass_three(bg_typ, fg_typ) 131 | schar bg_typ, fg_typ; 132 | { 133 | register int i,j; 134 | short count, dr; 135 | 136 | for(i=2; i<=WIDTH; i++) 137 | for(j=1; j<HEIGHT; j++) { 138 | for(count=0, dr=0; dr < 8; dr++) 139 | if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ) 140 | == fg_typ) 141 | count++; 142 | if (count < 3) 143 | new_loc(i,j) = bg_typ; 144 | else 145 | new_loc(i,j) = get_map(i,j, bg_typ); 146 | } 147 | 148 | for(i=2; i<=WIDTH; i++) 149 | for(j=1; j<HEIGHT; j++) 150 | levl[i][j].typ = new_loc(i,j); 151 | } 152 | 153 | /* 154 | * use a flooding algorithm to find all locations that should 155 | * have the same rm number as the current location. 156 | * if anyroom is TRUE, use IS_ROOM to check room membership instead of 157 | * exactly matching levl[sx][sy].typ and walls are included as well. 158 | */ 159 | void 160 | flood_fill_rm(sx, sy, rmno, lit, anyroom) 161 | int sx; 162 | register int sy; 163 | register int rmno; 164 | boolean lit; 165 | boolean anyroom; 166 | { 167 | register int i; 168 | int nx; 169 | schar fg_typ = levl[sx][sy].typ; 170 | 171 | /* back up to find leftmost uninitialized location */ 172 | while (sx > 0 && 173 | (anyroom ? IS_ROOM(levl[sx][sy].typ) : levl[sx][sy].typ == fg_typ) && 174 | (int) levl[sx][sy].roomno != rmno) 175 | sx--; 176 | sx++; /* compensate for extra decrement */ 177 | 178 | /* assume sx,sy is valid */ 179 | if(sx < min_rx) min_rx = sx; 180 | if(sy < min_ry) min_ry = sy; 181 | 182 | for(i=sx; i<=WIDTH && levl[i][sy].typ == fg_typ; i++) { 183 | levl[i][sy].roomno = rmno; 184 | levl[i][sy].lit = lit; 185 | if(anyroom) { 186 | /* add walls to room as well */ 187 | register int ii,jj; 188 | for(ii= (i == sx ? i-1 : i); ii <= i+1; ii++) 189 | for(jj = sy-1; jj <= sy+1; jj++) 190 | if(isok(ii,jj) && 191 | (IS_WALL(levl[ii][jj].typ) || 192 | IS_DOOR(levl[ii][jj].typ))) { 193 | levl[ii][jj].edge = 1; 194 | if(lit) levl[ii][jj].lit = lit; 195 | if ((int) levl[ii][jj].roomno != rmno) 196 | levl[ii][jj].roomno = SHARED; 197 | } 198 | } 199 | n_loc_filled++; 200 | } 201 | nx = i; 202 | 203 | if(isok(sx,sy-1)) { 204 | for(i=sx; i<nx; i++) 205 | if(levl[i][sy-1].typ == fg_typ) { 206 | if ((int) levl[i][sy-1].roomno != rmno) 207 | flood_fill_rm(i,sy-1,rmno,lit,anyroom); 208 | } else { 209 | if((i>sx || isok(i-1,sy-1)) && 210 | levl[i-1][sy-1].typ == fg_typ) { 211 | if ((int) levl[i-1][sy-1].roomno != rmno) 212 | flood_fill_rm(i-1,sy-1,rmno,lit,anyroom); 213 | } 214 | if((i<nx-1 || isok(i+1,sy-1)) && 215 | levl[i+1][sy-1].typ == fg_typ) { 216 | if ((int) levl[i+1][sy-1].roomno != rmno) 217 | flood_fill_rm(i+1,sy-1,rmno,lit,anyroom); 218 | } 219 | } 220 | } 221 | if(isok(sx,sy+1)) { 222 | for(i=sx; i<nx; i++) 223 | if(levl[i][sy+1].typ == fg_typ) { 224 | if ((int) levl[i][sy+1].roomno != rmno) 225 | flood_fill_rm(i,sy+1,rmno,lit,anyroom); 226 | } else { 227 | if((i>sx || isok(i-1,sy+1)) && 228 | levl[i-1][sy+1].typ == fg_typ) { 229 | if ((int) levl[i-1][sy+1].roomno != rmno) 230 | flood_fill_rm(i-1,sy+1,rmno,lit,anyroom); 231 | } 232 | if((i<nx-1 || isok(i+1,sy+1)) && 233 | levl[i+1][sy+1].typ == fg_typ) { 234 | if ((int) levl[i+1][sy+1].roomno != rmno) 235 | flood_fill_rm(i+1,sy+1,rmno,lit,anyroom); 236 | } 237 | } 238 | } 239 | 240 | if(nx > max_rx) max_rx = nx - 1; /* nx is just past valid region */ 241 | if(sy > max_ry) max_ry = sy; 242 | } 243 | 244 | /* 245 | * If we have drawn a map without walls, this allows us to 246 | * auto-magically wallify it. Taken from lev_main.c. 247 | */ 248 | STATIC_OVL void 249 | wallify_map() 250 | { 251 | 252 | int x, y, xx, yy; 253 | 254 | for(x = 1; x < COLNO; x++) 255 | for(y = 0; y < ROWNO; y++) 256 | if(levl[x][y].typ == STONE) { 257 | for(yy = y - 1; yy <= y+1; yy++) 258 | for(xx = x - 1; xx <= x+1; xx++) 259 | if(isok(xx,yy) && levl[xx][yy].typ == ROOM) { 260 | if(yy != y) levl[x][y].typ = HWALL; 261 | else levl[x][y].typ = VWALL; 262 | } 263 | } 264 | } 265 | 266 | STATIC_OVL void 267 | join_map(bg_typ, fg_typ) 268 | schar bg_typ, fg_typ; 269 | { 270 | register struct mkroom *croom, *croom2; 271 | 272 | register int i, j; 273 | int sx, sy; 274 | coord sm, em; 275 | 276 | /* first, use flood filling to find all of the regions that need joining */ 277 | for(i=2; i<=WIDTH; i++) 278 | for(j=1; j<HEIGHT; j++) { 279 | if(levl[i][j].typ == fg_typ && levl[i][j].roomno == NO_ROOM) { 280 | min_rx = max_rx = i; 281 | min_ry = max_ry = j; 282 | n_loc_filled = 0; 283 | flood_fill_rm(i,j,nroom+ROOMOFFSET,FALSE,FALSE); 284 | if(n_loc_filled > 3) { 285 | add_room(min_rx, min_ry, max_rx, max_ry, 286 | FALSE, OROOM, TRUE); 287 | rooms[nroom-1].irregular = TRUE; 288 | if(nroom >= (MAXNROFROOMS*2)) 289 | goto joinm; 290 | } else { 291 | /* 292 | * it's a tiny hole; erase it from the map to avoid 293 | * having the player end up here with no way out. 294 | */ 295 | for(sx = min_rx; sx<=max_rx; sx++) 296 | for(sy = min_ry; sy<=max_ry; sy++) 297 | if ((int) levl[sx][sy].roomno == 298 | nroom + ROOMOFFSET) { 299 | levl[sx][sy].typ = bg_typ; 300 | levl[sx][sy].roomno = NO_ROOM; 301 | } 302 | } 303 | } 304 | } 305 | 306 | joinm: 307 | /* 308 | * Ok, now we can actually join the regions with fg_typ's. 309 | * The rooms are already sorted due to the previous loop, 310 | * so don't call sort_rooms(), which can screw up the roomno's 311 | * validity in the levl structure. 312 | */ 313 | for(croom = &rooms[0], croom2 = croom + 1; croom2 < &rooms[nroom]; ) { 314 | /* pick random starting and end locations for "corridor" */ 315 | if(!somexy(croom, &sm) || !somexy(croom2, &em)) { 316 | /* ack! -- the level is going to be busted */ 317 | /* arbitrarily pick centers of both rooms and hope for the best */ 318 | impossible("No start/end room loc in join_map."); 319 | sm.x = croom->lx + ((croom->hx - croom->lx) / 2); 320 | sm.y = croom->ly + ((croom->hy - croom->ly) / 2); 321 | em.x = croom2->lx + ((croom2->hx - croom2->lx) / 2); 322 | em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2); 323 | } 324 | 325 | (void) dig_corridor(&sm, &em, FALSE, fg_typ, bg_typ); 326 | 327 | /* choose next region to join */ 328 | /* only increment croom if croom and croom2 are non-overlapping */ 329 | if(croom2->lx > croom->hx || 330 | ((croom2->ly > croom->hy || croom2->hy < croom->ly) && rn2(3))) { 331 | croom = croom2; 332 | } 333 | croom2++; /* always increment the next room */ 334 | } 335 | } 336 | 337 | STATIC_OVL void 338 | finish_map(fg_typ, bg_typ, lit, walled) 339 | schar fg_typ, bg_typ; 340 | boolean lit, walled; 341 | { 342 | int i, j; 343 | 344 | if(walled) wallify_map(); 345 | 346 | if(lit) { 347 | for(i=1; i<COLNO; i++) 348 | for(j=0; j<ROWNO; j++) 349 | if((!IS_ROCK(fg_typ) && levl[i][j].typ == fg_typ) || 350 | (!IS_ROCK(bg_typ) && levl[i][j].typ == bg_typ) || 351 | (walled && IS_WALL(levl[i][j].typ))) 352 | levl[i][j].lit = TRUE; 353 | for(i = 0; i < nroom; i++) 354 | rooms[i].rlit = 1; 355 | } 356 | /* light lava even if everything's otherwise unlit */ 357 | for(i=1; i<COLNO; i++) 358 | for(j=0; j<ROWNO; j++) 359 | if (levl[i][j].typ == LAVAPOOL) 360 | levl[i][j].lit = TRUE; 361 | } 362 | 363 | #define N_P1_ITER 1 /* tune map generation via this value */ 364 | #define N_P2_ITER 1 /* tune map generation via this value */ 365 | #define N_P3_ITER 2 /* tune map smoothing via this value */ 366 | 367 | void 368 | mkmap(init_lev) 369 | 370 | lev_init *init_lev; 371 | { 372 | schar bg_typ = init_lev->bg, 373 | fg_typ = init_lev->fg; 374 | boolean smooth = init_lev->smoothed, 375 | join = init_lev->joined; 376 | xchar lit = init_lev->lit, 377 | walled = init_lev->walled; 378 | int i; 379 | 380 | if(lit < 0) 381 | lit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? 1 : 0; 382 | 383 | new_locations = (char *)alloc((WIDTH+1) * HEIGHT); 384 | 385 | init_map(bg_typ); 386 | init_fill(bg_typ, fg_typ); 387 | 388 | for(i = 0; i < N_P1_ITER; i++) 389 | pass_one(bg_typ, fg_typ); 390 | 391 | for(i = 0; i < N_P2_ITER; i++) 392 | pass_two(bg_typ, fg_typ); 393 | 394 | if(smooth) 395 | for(i = 0; i < N_P3_ITER; i++) 396 | pass_three(bg_typ, fg_typ); 397 | 398 | if(join) 399 | join_map(bg_typ, fg_typ); 400 | 401 | finish_map(fg_typ, bg_typ, (boolean)lit, (boolean)walled); 402 | /* a walled, joined level is cavernous, not mazelike -dlc */ 403 | if (walled && join) { 404 | level.flags.is_maze_lev = FALSE; 405 | level.flags.is_cavernous_lev = TRUE; 406 | } 407 | free(new_locations); 408 | } 409 | 410 | /*mkmap.c*/