1 /* SCCS Id: @(#)mkmap.c 3.4 1996/05/23 */
2 /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
8 #define HEIGHT (ROWNO - 1)
9 #define WIDTH (COLNO - 2)
11 STATIC_DCL
void init_map(SCHAR_P
);
12 STATIC_DCL
void init_fill(SCHAR_P
,SCHAR_P
);
13 STATIC_DCL schar
get_map(int,int,SCHAR_P
);
14 STATIC_DCL
void pass_one(SCHAR_P
,SCHAR_P
);
15 STATIC_DCL
void pass_two(SCHAR_P
,SCHAR_P
);
16 STATIC_DCL
void pass_three(SCHAR_P
,SCHAR_P
);
17 STATIC_DCL
void wallify_map(void);
18 STATIC_DCL
void join_map(SCHAR_P
,SCHAR_P
);
19 STATIC_DCL
void finish_map(SCHAR_P
,SCHAR_P
,XCHAR_P
,XCHAR_P
);
20 STATIC_DCL
void remove_room(unsigned);
21 void mkmap(lev_init
*);
24 int min_rx
, max_rx
, min_ry
, max_ry
; /* rectangle bounds for regions */
25 static int n_loc_filled
;
33 for(i
=1; i
<COLNO
; i
++)
34 for(j
=0; j
<ROWNO
; j
++)
35 levl
[i
][j
].typ
= bg_typ
;
39 init_fill(bg_typ
, fg_typ
)
45 limit
= (WIDTH
* HEIGHT
* 2) / 5;
47 while(count
< limit
) {
50 if (levl
[i
][j
].typ
== bg_typ
) {
51 levl
[i
][j
].typ
= fg_typ
;
58 get_map(col
,row
, bg_typ
)
62 if (col
<= 0 || row
< 0 || col
> WIDTH
|| row
>= HEIGHT
)
64 return levl
[col
][row
].typ
;
67 static int dirs
[16] = {
68 -1, -1 /**/, -1, 0 /**/, -1, 1 /**/,
69 0, -1 /**/, 0, 1 /**/,
70 1, -1 /**/, 1, 0 /**/, 1, 1};
73 pass_one(bg_typ
, fg_typ
)
79 for(i
=2; i
<=WIDTH
; i
++)
80 for(j
=1; j
<HEIGHT
; j
++) {
81 for(count
=0, dr
=0; dr
< 8; dr
++)
82 if(get_map(i
+dirs
[dr
*2], j
+dirs
[(dr
*2)+1], bg_typ
)
90 levl
[i
][j
].typ
= bg_typ
;
96 levl
[i
][j
].typ
= fg_typ
;
104 #define new_loc(i,j) *(new_locations+ ((j)*(WIDTH+1)) + (i))
107 pass_two(bg_typ
, fg_typ
)
108 schar bg_typ
, fg_typ
;
113 for(i
=2; i
<=WIDTH
; i
++)
114 for(j
=1; j
<HEIGHT
; j
++) {
115 for(count
=0, dr
=0; dr
< 8; dr
++)
116 if(get_map(i
+dirs
[dr
*2], j
+dirs
[(dr
*2)+1], bg_typ
)
120 new_loc(i
,j
) = bg_typ
;
122 new_loc(i
,j
) = get_map(i
,j
, bg_typ
);
125 for(i
=2; i
<=WIDTH
; i
++)
126 for(j
=1; j
<HEIGHT
; j
++)
127 levl
[i
][j
].typ
= new_loc(i
,j
);
131 pass_three(bg_typ
, fg_typ
)
132 schar bg_typ
, fg_typ
;
137 for(i
=2; i
<=WIDTH
; i
++)
138 for(j
=1; j
<HEIGHT
; j
++) {
139 for(count
=0, dr
=0; dr
< 8; dr
++)
140 if(get_map(i
+dirs
[dr
*2], j
+dirs
[(dr
*2)+1], bg_typ
)
144 new_loc(i
,j
) = bg_typ
;
146 new_loc(i
,j
) = get_map(i
,j
, bg_typ
);
149 for(i
=2; i
<=WIDTH
; i
++)
150 for(j
=1; j
<HEIGHT
; j
++)
151 levl
[i
][j
].typ
= new_loc(i
,j
);
155 * use a flooding algorithm to find all locations that should
156 * have the same rm number as the current location.
157 * if anyroom is TRUE, use IS_ROOM to check room membership instead of
158 * exactly matching levl[sx][sy].typ and walls are included as well.
161 flood_fill_rm(sx
, sy
, rmno
, lit
, anyroom
)
170 schar fg_typ
= levl
[sx
][sy
].typ
;
172 /* back up to find leftmost uninitialized location */
174 (anyroom
? IS_ROOM(levl
[sx
][sy
].typ
) : levl
[sx
][sy
].typ
== fg_typ
) &&
175 (int) levl
[sx
][sy
].roomno
!= rmno
)
177 sx
++; /* compensate for extra decrement */
179 /* assume sx,sy is valid */
180 if(sx
< min_rx
) min_rx
= sx
;
181 if(sy
< min_ry
) min_ry
= sy
;
183 for(i
=sx
; i
<=WIDTH
&& levl
[i
][sy
].typ
== fg_typ
; i
++) {
184 levl
[i
][sy
].roomno
= rmno
;
185 levl
[i
][sy
].lit
= lit
;
187 /* add walls to room as well */
189 for(ii
= (i
== sx
? i
-1 : i
); ii
<= i
+1; ii
++)
190 for(jj
= sy
-1; jj
<= sy
+1; jj
++)
192 (IS_WALL(levl
[ii
][jj
].typ
) ||
193 IS_DOOR(levl
[ii
][jj
].typ
))) {
194 levl
[ii
][jj
].edge
= 1;
195 if(lit
) levl
[ii
][jj
].lit
= lit
;
196 if ((int) levl
[ii
][jj
].roomno
!= rmno
)
197 levl
[ii
][jj
].roomno
= SHARED
;
205 for(i
=sx
; i
<nx
; i
++) {
206 if(levl
[i
][sy
-1].typ
== fg_typ
) {
207 if ((int) levl
[i
][sy
-1].roomno
!= rmno
)
208 flood_fill_rm(i
,sy
-1,rmno
,lit
,anyroom
);
210 if((i
>sx
|| isok(i
-1,sy
-1)) &&
211 levl
[i
-1][sy
-1].typ
== fg_typ
) {
212 if ((int) levl
[i
-1][sy
-1].roomno
!= rmno
)
213 flood_fill_rm(i
-1,sy
-1,rmno
,lit
,anyroom
);
215 if((i
<nx
-1 || isok(i
+1,sy
-1)) &&
216 levl
[i
+1][sy
-1].typ
== fg_typ
) {
217 if ((int) levl
[i
+1][sy
-1].roomno
!= rmno
)
218 flood_fill_rm(i
+1,sy
-1,rmno
,lit
,anyroom
);
224 for(i
=sx
; i
<nx
; i
++) {
225 if(levl
[i
][sy
+1].typ
== fg_typ
) {
226 if ((int) levl
[i
][sy
+1].roomno
!= rmno
)
227 flood_fill_rm(i
,sy
+1,rmno
,lit
,anyroom
);
229 if((i
>sx
|| isok(i
-1,sy
+1)) &&
230 levl
[i
-1][sy
+1].typ
== fg_typ
) {
231 if ((int) levl
[i
-1][sy
+1].roomno
!= rmno
)
232 flood_fill_rm(i
-1,sy
+1,rmno
,lit
,anyroom
);
234 if((i
<nx
-1 || isok(i
+1,sy
+1)) &&
235 levl
[i
+1][sy
+1].typ
== fg_typ
) {
236 if ((int) levl
[i
+1][sy
+1].roomno
!= rmno
)
237 flood_fill_rm(i
+1,sy
+1,rmno
,lit
,anyroom
);
242 if(nx
> max_rx
) max_rx
= nx
- 1; /* nx is just past valid region */
243 if(sy
> max_ry
) max_ry
= sy
;
247 * If we have drawn a map without walls, this allows us to
248 * auto-magically wallify it. Taken from lev_main.c.
256 for(x
= 1; x
< COLNO
; x
++)
257 for(y
= 0; y
< ROWNO
; y
++)
258 if(levl
[x
][y
].typ
== STONE
) {
259 for(yy
= y
- 1; yy
<= y
+1; yy
++)
260 for(xx
= x
- 1; xx
<= x
+1; xx
++)
261 if(isok(xx
,yy
) && levl
[xx
][yy
].typ
== ROOM
) {
262 if(yy
!= y
) levl
[x
][y
].typ
= HWALL
;
263 else levl
[x
][y
].typ
= VWALL
;
269 join_map(bg_typ
, fg_typ
)
270 schar bg_typ
, fg_typ
;
272 register struct mkroom
*croom
, *croom2
;
278 /* first, use flood filling to find all of the regions that need joining */
279 for(i
=2; i
<=WIDTH
; i
++)
280 for(j
=1; j
<HEIGHT
; j
++) {
281 if(levl
[i
][j
].typ
== fg_typ
&& levl
[i
][j
].roomno
== NO_ROOM
) {
285 flood_fill_rm(i
,j
,nroom
+ROOMOFFSET
,FALSE
,FALSE
);
286 if(n_loc_filled
> 3) {
287 add_room(min_rx
, min_ry
, max_rx
, max_ry
,
288 FALSE
, OROOM
, TRUE
, FALSE
, FALSE
);
289 rooms
[nroom
-1].irregular
= TRUE
;
290 if(nroom
>= (MAXNROFROOMS
*2))
294 * it's a tiny hole; erase it from the map to avoid
295 * having the player end up here with no way out.
297 for(sx
= min_rx
; sx
<=max_rx
; sx
++)
298 for(sy
= min_ry
; sy
<=max_ry
; sy
++)
299 if ((int) levl
[sx
][sy
].roomno
==
300 nroom
+ ROOMOFFSET
) {
301 levl
[sx
][sy
].typ
= bg_typ
;
302 levl
[sx
][sy
].roomno
= NO_ROOM
;
310 * Ok, now we can actually join the regions with fg_typ's.
311 * The rooms are already sorted due to the previous loop,
312 * so don't call sort_rooms(), which can screw up the roomno's
313 * validity in the levl structure.
315 for(croom
= &rooms
[0], croom2
= croom
+ 1; croom2
< &rooms
[nroom
]; ) {
316 /* pick random starting and end locations for "corridor" */
317 if(!somexy(croom
, &sm
) || !somexy(croom2
, &em
)) {
318 /* ack! -- the level is going to be busted */
319 /* arbitrarily pick centers of both rooms and hope for the best */
320 impossible("No start/end room loc in join_map.");
321 sm
.x
= croom
->lx
+ ((croom
->hx
- croom
->lx
) / 2);
322 sm
.y
= croom
->ly
+ ((croom
->hy
- croom
->ly
) / 2);
323 em
.x
= croom2
->lx
+ ((croom2
->hx
- croom2
->lx
) / 2);
324 em
.y
= croom2
->ly
+ ((croom2
->hy
- croom2
->ly
) / 2);
327 (void) dig_corridor(&sm
, &em
, FALSE
, fg_typ
, bg_typ
);
329 /* choose next region to join */
330 /* only increment croom if croom and croom2 are non-overlapping */
331 if(croom2
->lx
> croom
->hx
||
332 ((croom2
->ly
> croom
->hy
|| croom2
->hy
< croom
->ly
) && rn2(3))) {
335 croom2
++; /* always increment the next room */
340 finish_map(fg_typ
, bg_typ
, lit
, walled
)
341 schar fg_typ
, bg_typ
;
346 if(walled
) wallify_map();
349 for(i
=1; i
<COLNO
; i
++)
350 for(j
=0; j
<ROWNO
; j
++)
351 if((!IS_ROCK(fg_typ
) && levl
[i
][j
].typ
== fg_typ
) ||
352 (!IS_ROCK(bg_typ
) && levl
[i
][j
].typ
== bg_typ
) ||
353 (bg_typ
== TREE
&& levl
[i
][j
].typ
== bg_typ
) ||
354 (walled
&& IS_WALL(levl
[i
][j
].typ
)))
355 levl
[i
][j
].lit
= TRUE
;
356 for(i
= 0; i
< nroom
; i
++)
359 /* light lava even if everything's otherwise unlit */
360 for(i
=1; i
<COLNO
; i
++)
361 for(j
=0; j
<ROWNO
; j
++)
362 if (levl
[i
][j
].typ
== LAVAPOOL
)
363 levl
[i
][j
].lit
= TRUE
;
367 * When level processed by join_map is overlaid by a MAP, some rooms may no
368 * longer be valid. All rooms in the region lx <= x < hx, ly <= y < hy are
369 * removed. Rooms partially in the region are truncated. This function
370 * must be called before the REGIONs or ROOMs of the map are processed, or
371 * those rooms will be removed as well. Assumes roomno fields in the
372 * region are already cleared, and roomno and irregular fields outside the
373 * region are all set.
376 remove_rooms(lx
, ly
, hx
, hy
)
380 struct mkroom
*croom
;
382 for (i
= nroom
- 1; i
>= 0; --i
) {
384 if (croom
->hx
< lx
|| croom
->lx
>= hx
||
385 croom
->hy
< ly
|| croom
->ly
>= hy
) continue; /* no overlap */
387 if (croom
->lx
< lx
|| croom
->hx
>= hx
||
388 croom
->ly
< ly
|| croom
->hy
>= hy
) { /* partial overlap */
389 /* TODO: ensure remaining parts of room are still joined */
391 if (!croom
->irregular
) impossible("regular room in joined map");
393 /* total overlap, remove the room */
394 remove_room((unsigned)i
);
400 * Remove roomno from the rooms array, decrementing nroom. Also updates
401 * all level roomno values of affected higher numbered rooms. Assumes
402 * level structure contents corresponding to roomno have already been reset.
403 * Currently handles only the removal of rooms that have no subrooms.
409 struct mkroom
*croom
= &rooms
[roomno
];
410 struct mkroom
*maxroom
= &rooms
[--nroom
];
414 if (croom
!= maxroom
) {
415 /* since the order in the array only matters for making corridors,
416 * copy the last room over the one being removed on the assumption
417 * that corridors have already been dug. */
418 (void) memcpy((void *)croom
, (void *)maxroom
,
419 sizeof(struct mkroom
));
421 /* since maxroom moved, update affected level roomno values */
422 oroomno
= nroom
+ ROOMOFFSET
;
423 roomno
+= ROOMOFFSET
;
424 for (i
= croom
->lx
; i
<= croom
->hx
; ++i
)
425 for (j
= croom
->ly
; j
<= croom
->hy
; ++j
) {
426 if (levl
[i
][j
].roomno
== oroomno
)
427 levl
[i
][j
].roomno
= roomno
;
430 maxroom
->hx
= -1; /* just like add_room */
433 #define N_P1_ITER 1 /* tune map generation via this value */
434 #define N_P2_ITER 1 /* tune map generation via this value */
435 #define N_P3_ITER 2 /* tune map smoothing via this value */
441 schar bg_typ
= init_lev
->bg
,
442 fg_typ
= init_lev
->fg
;
443 boolean smooth
= init_lev
->smoothed
,
444 join
= init_lev
->joined
;
445 xchar lit
= init_lev
->lit
,
446 walled
= init_lev
->walled
;
450 lit
= (rnd(1+abs(depth(&u
.uz
))) < 11 && rn2(77)) ? 1 : 0;
452 new_locations
= (char *)alloc((WIDTH
+1) * HEIGHT
);
455 init_fill(bg_typ
, fg_typ
);
457 for(i
= 0; i
< N_P1_ITER
; i
++)
458 pass_one(bg_typ
, fg_typ
);
460 for(i
= 0; i
< N_P2_ITER
; i
++)
461 pass_two(bg_typ
, fg_typ
);
464 for(i
= 0; i
< N_P3_ITER
; i
++)
465 pass_three(bg_typ
, fg_typ
);
468 join_map(bg_typ
, fg_typ
);
470 finish_map(fg_typ
, bg_typ
, (boolean
)lit
, (boolean
)walled
);
471 /* a walled, joined level is cavernous, not mazelike -dlc */
472 if (walled
&& join
) {
473 level
.flags
.is_maze_lev
= FALSE
;
474 level
.flags
.is_cavernous_lev
= TRUE
;