Blindfold removal fix
[slashemextended.git] / src / mkmaze.c
blob9ecb252644ddb7d0d49f2ddcb84109b8ce88f250
1 /* SCCS Id: @(#)mkmaze.c 3.4 2002/04/04 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include "sp_lev.h"
7 #include "lev.h" /* save & restore info */
9 /* from sp_lev.c, for fixup_special() */
10 extern char *lev_message;
11 extern lev_region *lregions;
12 extern int num_lregions;
14 STATIC_DCL boolean iswall(int,int);
15 STATIC_DCL boolean iswall_or_stone(int,int);
16 STATIC_DCL boolean is_solid(int,int);
17 STATIC_DCL int extend_spine(int [3][3], int, int, int);
18 STATIC_DCL boolean okay(int,int,int);
19 STATIC_DCL void maze0xy(coord *);
20 STATIC_DCL boolean put_lregion_here(XCHAR_P,XCHAR_P,XCHAR_P,
21 XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,BOOLEAN_P,d_level *);
22 STATIC_DCL boolean really_put_lregion_here(XCHAR_P,XCHAR_P,XCHAR_P,
23 XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,BOOLEAN_P,d_level *);
24 STATIC_DCL void fixup_special(void);
25 STATIC_DCL void move(int *,int *,int);
26 STATIC_DCL void setup_waterlevel(void);
27 STATIC_DCL void unsetup_waterlevel(void);
29 STATIC_OVL boolean
30 iswall(x,y)
31 int x,y;
33 register int type;
35 if (!isok(x,y)) return FALSE;
36 type = levl[x][y].typ;
37 return (IS_WALL(type) || IS_DOOR(type) ||
38 type == SDOOR || type == IRONBARS);
41 STATIC_OVL boolean
42 iswall_or_stone(x,y)
43 int x,y;
45 register int type;
47 /* out of bounds = stone */
48 if (!isok(x,y)) return TRUE;
50 type = levl[x][y].typ;
51 return (type == STONE || IS_WALL(type) || IS_DOOR(type) ||
52 type == SDOOR || type == IRONBARS);
55 /* return TRUE if out of bounds, wall or rock */
56 STATIC_OVL boolean
57 is_solid(x,y)
58 int x, y;
60 return (!isok(x,y) || IS_STWALL(levl[x][y].typ));
65 * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend
66 * a wall spine in the (dx,dy) direction. Return 0 otherwise.
68 * To extend a wall spine in that direction, first there must be a wall there.
69 * Then, extend a spine unless the current position is surrounded by walls
70 * in the direction given by (dx,dy). E.g. if 'x' is our location, 'W'
71 * a wall, '.' a room, 'a' anything (we don't care), and our direction is
72 * (0,1) - South or down - then:
74 * a a a
75 * W x W This would not extend a spine from x down
76 * W W W (a corridor of walls is formed).
78 * a a a
79 * W x W This would extend a spine from x down.
80 * . W W
82 STATIC_OVL int
83 extend_spine(locale, wall_there, dx, dy)
84 int locale[3][3];
85 int wall_there, dx, dy;
87 int spine, nx, ny;
89 nx = 1 + dx;
90 ny = 1 + dy;
92 if (wall_there) { /* wall in that direction */
93 if (dx) {
94 if (locale[ 1][0] && locale[ 1][2] && /* EW are wall/stone */
95 locale[nx][0] && locale[nx][2]) { /* diag are wall/stone */
96 spine = 0;
97 } else {
98 spine = 1;
100 } else { /* dy */
101 if (locale[0][ 1] && locale[2][ 1] && /* NS are wall/stone */
102 locale[0][ny] && locale[2][ny]) { /* diag are wall/stone */
103 spine = 0;
104 } else {
105 spine = 1;
108 } else {
109 spine = 0;
112 return spine;
117 * Walls to surprise jaded Gehennom-haters :)
119 * Wall cleanup. This function turns all wall squares into 'floortype' squares.
121 STATIC_OVL
122 void
123 wallify_special(x1, y1, x2, y2, floortype)
124 int x1, y1, x2, y2;
125 int floortype; /* The 'wall' floortype */
127 uchar type;
128 register int x,y;
129 struct rm *lev;
131 int density = 3 + rn2(8);
132 if (!rn2(5)) density += rnd(6);
133 if (!rn2(10)) density += rnd(15);
134 if (!rn2(25)) density += rnd(30);
135 if (!rn2(125)) density += rnd(40);
136 if (!rn2(750)) density += rnd(50);
138 /* sanity check on incoming variables */
139 if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2)
140 panic("wallify_fire: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2);
142 /* Translate the maze... */
143 for(x = x1; x <= x2; x++)
144 for(y = y1; y <= y2; y++) {
145 lev = &levl[x][y];
146 type = lev->typ;
147 if ( IS_WALL(type) && type != GRAVEWALL && (rnd(density) < 4))
148 lev->typ = (floortype == CROSSWALL) ? randomwalltype() : floortype;
149 else if IS_WALL(type)
150 lev->typ = STONE;
151 /* Doors become room squares. Does this make sense? */
152 else if (IS_DOOR(type))
153 lev->typ = ROOM;
154 else if (type == SDOOR)
155 lev->typ = ROOM;
156 else if (type == SCORR)
157 lev->typ = ROOM;
160 return;
164 * Wall cleanup. This function has two purposes: (1) remove walls that
165 * are totally surrounded by stone - they are redundant. (2) correct
166 * the types so that they extend and connect to each other.
168 STATIC_OVL
169 void
170 wallify_stone(x1, y1, x2, y2) /* [Lethe] Classic stone walls */
171 int x1, y1, x2, y2;
173 uchar type;
174 register int x,y;
175 struct rm *lev;
176 int bits;
177 int locale[3][3]; /* rock or wall status surrounding positions */
179 * Value 0 represents a free-standing wall. It could be anything,
180 * so even though this table says VWALL, we actually leave whatever
181 * typ was there alone.
183 static xchar spine_array[16] = {
184 VWALL, HWALL, HWALL, HWALL,
185 VWALL, TRCORNER, TLCORNER, TDWALL,
186 VWALL, BRCORNER, BLCORNER, TUWALL,
187 VWALL, TLWALL, TRWALL, CROSSWALL
190 /* sanity check on incoming variables */
191 if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2)
192 panic("wallify_stone: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2);
194 /* Step 1: change walls surrounded by rock to rock. */
195 for(x = x1; x <= x2; x++)
196 for(y = y1; y <= y2; y++) {
197 lev = &levl[x][y];
198 type = lev->typ;
199 if (IS_WALL(type) && type != DBWALL && type != ROCKWALL && type != TUNNELWALL && type != GRAVEWALL) {
200 if (is_solid(x-1,y-1) &&
201 is_solid(x-1,y ) &&
202 is_solid(x-1,y+1) &&
203 is_solid(x, y-1) &&
204 is_solid(x, y+1) &&
205 is_solid(x+1,y-1) &&
206 is_solid(x+1,y ) &&
207 is_solid(x+1,y+1))
208 lev->typ = STONE;
213 * Step 2: set the correct wall type. We can't combine steps
214 * 1 and 2 into a single sweep because we depend on knowing if
215 * the surrounding positions are stone.
217 for(x = x1; x <= x2; x++)
218 for(y = y1; y <= y2; y++) {
219 lev = &levl[x][y];
220 type = lev->typ;
221 if ( !(IS_WALL(type) && type != DBWALL && type != ROCKWALL && type != TUNNELWALL && type != GRAVEWALL)) continue;
223 /* set the locations TRUE if rock or wall or out of bounds */
224 locale[0][0] = iswall_or_stone(x-1,y-1);
225 locale[1][0] = iswall_or_stone( x,y-1);
226 locale[2][0] = iswall_or_stone(x+1,y-1);
228 locale[0][1] = iswall_or_stone(x-1, y);
229 locale[2][1] = iswall_or_stone(x+1, y);
231 locale[0][2] = iswall_or_stone(x-1,y+1);
232 locale[1][2] = iswall_or_stone( x,y+1);
233 locale[2][2] = iswall_or_stone(x+1,y+1);
235 /* determine if wall should extend to each direction NSEW */
236 bits = (extend_spine(locale, iswall(x,y-1), 0, -1) << 3)
237 | (extend_spine(locale, iswall(x,y+1), 0, 1) << 2)
238 | (extend_spine(locale, iswall(x+1,y), 1, 0) << 1)
239 | extend_spine(locale, iswall(x-1,y), -1, 0);
241 /* don't change typ if wall is free-standing */
242 if (bits) lev->typ = spine_array[bits];
247 * Wall cleanup. This selects an appropriate function to sort out the
248 * dungeon walls.
250 void
251 wallification(x1, y1, x2, y2, initial)
252 int x1, y1, x2, y2;
253 boolean initial;
255 /* Wallify normally unless creating a full maze level */
256 if (!initial) {
257 wallify_stone(x1, y1, x2, y2);
258 return;
261 /* Put in the walls... */
263 int wallchoice = rn2(450);
265 if (wallchoice < 417)
266 wallify_stone(x1, y1, x2, y2);
267 else if (wallchoice < 418)
268 wallify_special(x1, y1, x2, y2, CROSSWALL);
269 else if (wallchoice < 419)
270 wallify_special(x1, y1, x2, y2, CLOUD);
271 else if (wallchoice < 421)
272 wallify_special(x1, y1, x2, y2, MOAT);
273 else if (wallchoice < 423)
274 wallify_special(x1, y1, x2, y2, ICE);
275 else if (wallchoice < 425)
276 wallify_special(x1, y1, x2, y2, LAVAPOOL);
277 else if (wallchoice < 426)
278 wallify_special(x1, y1, x2, y2, TREE);
279 else if (wallchoice < 427)
280 wallify_special(x1, y1, x2, y2, GRAVEWALL);
281 else if (wallchoice < 428)
282 wallify_special(x1, y1, x2, y2, TUNNELWALL);
283 else if (wallchoice < 429)
284 wallify_special(x1, y1, x2, y2, FARMLAND);
285 else if (wallchoice < 430)
286 wallify_special(x1, y1, x2, y2, MOUNTAIN);
287 else if (wallchoice < 431)
288 wallify_special(x1, y1, x2, y2, WATERTUNNEL);
289 else if (wallchoice < 432)
290 wallify_special(x1, y1, x2, y2, CRYSTALWATER);
291 else if (wallchoice < 433)
292 wallify_special(x1, y1, x2, y2, MOORLAND);
293 else if (wallchoice < 434)
294 wallify_special(x1, y1, x2, y2, URINELAKE);
295 else if (wallchoice < 435)
296 wallify_special(x1, y1, x2, y2, SHIFTINGSAND);
297 else if (wallchoice < 436)
298 wallify_special(x1, y1, x2, y2, STYXRIVER);
299 else if (wallchoice < 437)
300 wallify_special(x1, y1, x2, y2, SNOW);
301 else if (wallchoice < 438)
302 wallify_special(x1, y1, x2, y2, ASH);
303 else if (wallchoice < 439)
304 wallify_special(x1, y1, x2, y2, SAND);
305 else if (wallchoice < 440)
306 wallify_special(x1, y1, x2, y2, PAVEDFLOOR);
307 else if (wallchoice < 441)
308 wallify_special(x1, y1, x2, y2, HIGHWAY);
309 else if (wallchoice < 442)
310 wallify_special(x1, y1, x2, y2, GRASSLAND);
311 else if (wallchoice < 443)
312 wallify_special(x1, y1, x2, y2, NETHERMIST);
313 else if (wallchoice < 444)
314 wallify_special(x1, y1, x2, y2, STALACTITE);
315 else if (wallchoice < 445)
316 wallify_special(x1, y1, x2, y2, CRYPTFLOOR);
317 else if (wallchoice < 446)
318 wallify_special(x1, y1, x2, y2, BUBBLES);
319 else if (wallchoice < 447)
320 wallify_special(x1, y1, x2, y2, RAINCLOUD);
321 else
322 wallify_special(x1, y1, x2, y2, IRONBARS);
324 return;
327 STATIC_OVL boolean
328 okay(x,y,dir)
329 int x,y;
330 register int dir;
332 move(&x,&y,dir);
333 move(&x,&y,dir);
334 if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0)
335 return(FALSE);
336 return(TRUE);
339 STATIC_OVL void
340 maze0xy(cc) /* find random starting point for maze generation */
341 coord *cc;
343 cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
344 cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
345 return;
349 * Bad if:
350 * pos is occupied OR
351 * pos is inside restricted region (lx,ly,hx,hy) OR
352 * NOT (pos is corridor and a maze level OR pos is a room OR pos is air)
354 boolean
355 bad_location(x, y, lx, ly, hx, hy)
356 xchar x, y;
357 xchar lx, ly, hx, hy;
359 return((boolean)(occupied(x, y) ||
360 within_bounded_area(x,y, lx,ly, hx,hy) ||
361 !((levl[x][y].typ == CORR /*&& level.flags.is_maze_lev*/) ||
362 levl[x][y].typ == ROOM || levl[x][y].typ == AIR || levl[x][y].typ == CLOUD || levl[x][y].typ == ICE || levl[x][y].typ == SNOW || levl[x][y].typ == ASH || levl[x][y].typ == SAND || levl[x][y].typ == PAVEDFLOOR || levl[x][y].typ == HIGHWAY || levl[x][y].typ == GRASSLAND || levl[x][y].typ == NETHERMIST || levl[x][y].typ == STALACTITE || levl[x][y].typ == CRYPTFLOOR || levl[x][y].typ == BUBBLES || levl[x][y].typ == RAINCLOUD)));
365 boolean
366 really_bad_location(x, y, lx, ly, hx, hy)
367 xchar x, y;
368 xchar lx, ly, hx, hy;
370 return((boolean) within_bounded_area(x,y, lx,ly, hx,hy) );
373 /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */
374 /* and place something (based on rtype) in that region */
375 void
376 place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev)
377 xchar lx, ly, hx, hy;
378 xchar nlx, nly, nhx, nhy;
379 xchar rtype;
380 d_level *lev;
382 int trycnt;
383 boolean oneshot;
384 xchar x, y;
386 if(!lx) { /* default to whole level */
388 * if there are rooms and this a branch, let place_branch choose
389 * the branch location (to avoid putting branches in corridors).
390 * Amy edit: but only if it's a plot-critical branch that you must find in order to win the game, and even then
391 * only if you're not playing the evil variant. Otherwise, let them be randomly placed.
392 * Note that it's not a bug that the sanctum-to-yendortower portal is exempt - otherwise, we'd always place it
393 * either in the temple or the graveyard, which we definitely don't want!
394 * Also, the flipside of those branches is free to be placed completely randomly, because you (normally) don't
395 * have to look for it - to any would-be slex modders reading this, I only want to avoid the player having to search
396 * the entirety of every level for branches that absolutely MUST be done to win the game.
397 * Stairseeker hybrid race should also allow them all to be placed randomly, like evilvariant mode
399 if(rtype == LR_BRANCH && nroom) {
401 if (!evilfriday && !isstairseeker && (at_dgn_entrance("Green Cross") || at_dgn_entrance("The Subquest") || at_dgn_entrance("The Quest") || at_dgn_entrance("Lawful Quest") || at_dgn_entrance("Neutral Quest") || at_dgn_entrance("Chaotic Quest") || at_dgn_entrance("The Elemental Planes") || at_dgn_entrance("Sheol") || at_dgn_entrance("Bell Caves") || at_dgn_entrance("Vlad's Tower") || at_dgn_entrance("Forging Chamber") || at_dgn_entrance("Dead Grounds") || at_dgn_entrance("Ordered Chaos") ) ) {
403 place_branch(Is_branchlev(&u.uz), 0, 0);
404 return;
410 lx = 1; hx = COLNO-1;
411 ly = 1; hy = ROWNO-1;
414 /* first a probabilistic approach */
416 oneshot = (lx == hx && ly == hy);
417 for (trycnt = 0; trycnt < 200; trycnt++) {
418 x = rn1((hx - lx) + 1, lx);
419 y = rn1((hy - ly) + 1, ly);
420 if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
421 return;
424 /* then a deterministic one */
426 oneshot = TRUE;
427 for (x = lx; x <= hx; x++)
428 for (y = ly; y <= hy; y++)
429 if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
430 return;
432 /* and finally, brute force the shit out of it because we're making a motherfucking BRANCH and the game might be
433 * rendered unwinnable if it cannot be placed! --Amy */
435 if (wizard) {
436 pline("Trying to force a location for lregion type %d", rtype);
439 oneshot = TRUE;
440 for (x = lx; x <= hx; x++)
441 for (y = ly; y <= hy; y++)
442 if (really_put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
443 return;
445 impossible("Couldn't place lregion type %d!", rtype);
448 STATIC_OVL boolean
449 put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)
450 xchar x, y;
451 xchar nlx, nly, nhx, nhy;
452 xchar rtype;
453 boolean oneshot;
454 d_level *lev;
456 if (bad_location(x, y, nlx, nly, nhx, nhy)) {
457 if (!oneshot) {
458 return FALSE; /* caller should try again */
459 } else {
460 /* Must make do with the only location possible;
461 avoid failure due to a misplaced trap.
462 It might still fail if there's a dungeon feature here. */
463 struct trap *t = t_at(x,y);
465 if (t && t->ttyp != MAGIC_PORTAL) deltrap(t);
466 if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE;
469 switch (rtype) {
470 case LR_TELE:
471 case LR_UPTELE:
472 case LR_DOWNTELE:
473 /* "something" means the player in this case */
474 if(MON_AT(x, y)) {
475 /* move the monster if no choice, or just try again */
476 if(oneshot) (void) rloc(m_at(x,y), FALSE);
477 else return(FALSE);
479 u_on_newpos(x, y);
480 break;
481 case LR_PORTAL:
482 mkportal(x, y, lev->dnum, lev->dlevel);
483 break;
484 case LR_DOWNSTAIR:
485 case LR_UPSTAIR:
486 mkstairs(x, y, (char)rtype, (struct mkroom *)0);
487 break;
488 case LR_BRANCH:
489 place_branch(Is_branchlev(&u.uz), x, y);
490 break;
492 return(TRUE);
495 STATIC_OVL boolean
496 really_put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)
497 xchar x, y;
498 xchar nlx, nly, nhx, nhy;
499 xchar rtype;
500 boolean oneshot;
501 d_level *lev;
503 if (really_bad_location(x, y, nlx, nly, nhx, nhy)) {
504 if (!oneshot) {
505 return FALSE; /* caller should try again */
506 } else {
507 /* Must make do with the only location possible;
508 avoid failure due to a misplaced trap.
509 It may not fail, no matter what happens. Missing ladder + lost soul mode == unwinnable game! --Amy */
510 struct trap *t = t_at(x,y);
512 if (t && t->ttyp != MAGIC_PORTAL) deltrap(t);
513 if (really_bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE;
516 switch (rtype) {
517 case LR_TELE:
518 case LR_UPTELE:
519 case LR_DOWNTELE:
520 /* "something" means the player in this case */
521 if(MON_AT(x, y)) {
522 /* move the monster if no choice, or just try again */
523 if(oneshot) (void) rloc(m_at(x,y), FALSE);
524 else return(FALSE);
526 u_on_newpos(x, y);
527 break;
528 case LR_PORTAL:
529 mkportal(x, y, lev->dnum, lev->dlevel);
530 break;
531 case LR_DOWNSTAIR:
532 case LR_UPSTAIR:
533 mkstairs(x, y, (char)rtype, (struct mkroom *)0);
534 break;
535 case LR_BRANCH:
536 place_branch(Is_branchlev(&u.uz), x, y);
537 break;
539 return(TRUE);
542 static boolean was_waterlevel; /* ugh... this shouldn't be needed */
544 /* this is special stuff that the level compiler cannot (yet) handle */
545 STATIC_OVL void
546 fixup_special()
548 register lev_region *r = lregions;
549 struct d_level lev;
550 register int x, y;
551 struct mkroom *croom;
552 boolean added_branch = FALSE;
554 if (was_waterlevel) {
555 was_waterlevel = FALSE;
556 u.uinwater = 0;
557 unsetup_waterlevel();
558 } else if (Is_waterlevel(&u.uz)) {
559 level.flags.hero_memory = 0;
560 was_waterlevel = TRUE;
561 /* water level is an odd beast - it has to be set up
562 before calling place_lregions etc. */
563 setup_waterlevel();
565 for(x = 0; x < num_lregions; x++, r++) {
566 switch(r->rtype) {
567 case LR_BRANCH:
568 added_branch = TRUE;
569 goto place_it;
571 case LR_PORTAL:
572 if(*r->rname.str >= '0' && *r->rname.str <= '9') {
573 /* "chutes and ladders" */
574 lev = u.uz;
575 lev.dlevel = atoi(r->rname.str);
576 } else {
577 s_level *sp = find_level(r->rname.str);
578 lev = sp->dlevel;
580 /* fall into... */
582 case LR_UPSTAIR:
583 case LR_DOWNSTAIR:
584 place_it:
585 place_lregion(r->inarea.x1, r->inarea.y1,
586 r->inarea.x2, r->inarea.y2,
587 r->delarea.x1, r->delarea.y1,
588 r->delarea.x2, r->delarea.y2,
589 r->rtype, &lev);
590 break;
592 case LR_TELE:
593 case LR_UPTELE:
594 case LR_DOWNTELE:
595 /* save the region outlines for goto_level() */
596 if(r->rtype == LR_TELE || r->rtype == LR_UPTELE) {
597 updest.lx = r->inarea.x1; updest.ly = r->inarea.y1;
598 updest.hx = r->inarea.x2; updest.hy = r->inarea.y2;
599 updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1;
600 updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2;
602 if(r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) {
603 dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1;
604 dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2;
605 dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1;
606 dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2;
608 /* place_lregion gets called from goto_level() */
609 break;
612 if (r->rname.str) free((void *) r->rname.str), r->rname.str = 0;
615 /* place dungeon branch if not placed above */
616 if (!added_branch && Is_branchlev(&u.uz)) {
617 place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH,(d_level *)0);
620 /* KMH -- arboreal levels */
621 /* if (level.flags.arboreal)
622 for(x = 2; x < x_maze_max; x++)
623 for(y = 2; y < y_maze_max; y++)
624 if (levl[x][y].typ == STONE)
625 levl[x][y].typ = TREE;*/
627 /* KMH -- Sokoban levels */
628 if(In_sokoban(&u.uz))
629 sokoban_detect();
631 /* Still need to add some stuff to level file */
632 if (Is_medusa_level(&u.uz)) {
633 struct obj *otmp;
634 int tryct;
636 croom = &rooms[0]; /* only one room on the medusa level */
637 for (tryct = rnd(4); tryct; tryct--) {
638 x = somex(croom); y = somey(croom);
639 if (goodpos(x, y, (struct monst *)0, 0)) {
640 otmp = mk_tt_object(STATUE, x, y);
641 while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) ||
642 pm_resistance(&mons[otmp->corpsenm],MR_STONE))) {
643 otmp->corpsenm = rndmonnum();
644 otmp->owt = weight(otmp);
649 if (rn2(2))
650 otmp = mk_tt_object(STATUE, somex(croom), somey(croom));
651 else /* Medusa statues don't contain books */
652 otmp = mkcorpstat(STATUE, (struct monst *)0, (struct permonst *)0,
653 somex(croom), somey(croom), FALSE);
654 if (otmp) {
655 while (pm_resistance(&mons[otmp->corpsenm],MR_STONE)
656 || poly_when_stoned(&mons[otmp->corpsenm])) {
657 otmp->corpsenm = rndmonnum();
658 otmp->owt = weight(otmp);
661 } else if(Is_wiz1_level(&u.uz)) {
662 croom = search_special(MORGUE);
664 create_secret_door(croom, W_SOUTH|W_EAST|W_WEST);
665 } else if(Is_knox(&u.uz)) {
666 /* using an unfilled morgue for rm id */
667 croom = search_special(MORGUE);
668 /* avoid inappropriate morgue-related messages */
669 level.flags.graveyard = level.flags.has_morgue = 0;
670 croom->rtype = OROOM; /* perhaps it should be set to VAULT? */
671 /* stock the main vault */
672 for(x = croom->lx; x <= croom->hx; x++)
673 for(y = croom->ly; y <= croom->hy; y++) {
674 (void) mkgold((long) rn1(300, 600), x, y);
675 if (!rn2(3) && !is_waterypool(x,y))
676 (void)maketrap(x, y, rn2(3) ? LANDMINE : SPIKED_PIT, 5, TRUE);
678 } else if (Role_if(PM_PRIEST) && In_quest(&u.uz)) {
679 /* less chance for undead corpses (lured from lower morgues) */
680 level.flags.graveyard = 1;
681 } else if (Is_stronghold(&u.uz)) {
682 level.flags.graveyard = 1;
683 } else if(Is_sanctum(&u.uz)) {
684 croom = search_special(TEMPLE);
686 create_secret_door(croom, W_ANY);
687 } else if(on_level(&u.uz, &orcus_level)) {
688 register struct monst *mtmp, *mtmp2;
690 /* it's a ghost town, get rid of shopkeepers */
691 for(mtmp = fmon; mtmp; mtmp = mtmp2) {
692 mtmp2 = mtmp->nmon;
693 if(mtmp->isshk) mongone(mtmp);
697 if(lev_message) {
698 char *str, *nl;
699 for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) {
700 *nl = '\0';
701 pline("%s", str);
703 if(*str)
704 pline("%s", str);
705 free((void *)lev_message);
706 lev_message = 0;
709 if (lregions)
710 free((void *) lregions), lregions = 0;
711 num_lregions = 0;
715 * Select a random coordinate in the maze.
717 * We want a place not 'touched' by the loader. That is, a place in
718 * the maze outside every part of the special level.
721 void
722 makemaz(s)
723 register const char *s;
725 int x,y;
726 char protofile[20];
727 s_level *sp = Is_special(&u.uz);
728 coord mm;
729 struct monst *mtmp;
731 if(*s) {
732 if(sp && sp->rndlevs) sprintf(protofile, "%s-%d", s,
733 rnd((int) sp->rndlevs));
734 else strcpy(protofile, s);
735 } else if(*(dungeons[u.uz.dnum].proto)) {
736 if(dunlevs_in_dungeon(&u.uz) > 1) {
737 if(sp && sp->rndlevs)
738 sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto,
739 dunlev(&u.uz),
740 rnd((int) sp->rndlevs));
741 else sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto,
742 dunlev(&u.uz));
743 } else if(sp && sp->rndlevs) {
744 sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto,
745 rnd((int) sp->rndlevs));
746 } else strcpy(protofile, dungeons[u.uz.dnum].proto);
748 } else strcpy(protofile, "");
750 #ifdef WIZARD
751 /* SPLEVTYPE format is "level-choice,level-choice"... */
752 if (wizard && *protofile && sp && sp->rndlevs) {
753 char *ep = getenv("SPLEVTYPE"); /* not nh_getenv */
754 if (ep) {
755 /* rindex always succeeds due to code in prior block */
756 int len = (rindex(protofile, '-') - protofile) + 1;
758 while (ep && *ep) {
759 if (!strncmp(ep, protofile, len)) {
760 int pick = atoi(ep + len);
761 /* use choice only if valid */
762 if (pick > 0 && pick <= (int) sp->rndlevs)
763 sprintf(protofile + len, "%d", pick);
764 break;
765 } else {
766 ep = index(ep, ',');
767 if (ep) ++ep;
772 #endif
774 if(*protofile) {
775 strcat(protofile, LEV_EXT);
776 if(load_special(protofile)) {
777 fixup_special();
778 /* some levels can end up with monsters
779 on dead mon list, including light source monsters */
780 dmonsfree();
781 return; /* no mazification right now */
783 /* impossible("Couldn't load \"%s\" - making a maze.", protofile); */
784 if (strncmpi(protofile, "makemase.lev", 13) && strncmpi(protofile, "makemais.lev", 13) ) pline("Couldn't load \"%s\" - making a maze.", protofile);
787 if (rn2(2)) level.flags.is_maze_lev = TRUE;
789 #ifndef WALLIFIED_MAZE
790 for(x = 2; x < x_maze_max; x++)
791 for(y = 2; y < y_maze_max; y++)
792 levl[x][y].typ = STONE;
793 #else
794 for(x = 2; x <= x_maze_max; x++)
795 for(y = 2; y <= y_maze_max; y++)
796 levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
797 #endif
799 maze0xy(&mm);
800 walkfrom((int) mm.x, (int) mm.y);
801 /* put a boulder at the maze center */
802 (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE, FALSE, FALSE);
804 #ifdef WALLIFIED_MAZE
805 wallification(2, 2, x_maze_max, y_maze_max, TRUE);
806 #endif
807 mazexy_all(&mm);
808 mkstairs(mm.x, mm.y, 1, (struct mkroom *)0); /* up */
809 if (!Invocation_lev(&u.uz)) {
810 mazexy_all(&mm);
811 mkstairs(mm.x, mm.y, 0, (struct mkroom *)0); /* down */
812 } else { /* choose "vibrating square" location */
813 #define x_maze_min 2
814 #define y_maze_min 2
816 * Pick a position where the stairs down to Moloch's Sanctum
817 * level will ultimately be created. At that time, an area
818 * will be altered: walls removed, moat and traps generated,
819 * boulders destroyed. The position picked here must ensure
820 * that that invocation area won't extend off the map.
822 * We actually allow up to 2 squares around the usual edge of
823 * the area to get truncated; see mkinvokearea(mklev.c).
825 #define INVPOS_X_MARGIN (6 - 2)
826 #define INVPOS_Y_MARGIN (5 - 2)
827 #define INVPOS_DISTANCE 11
828 int x_range = x_maze_max - x_maze_min - 2*INVPOS_X_MARGIN - 1,
829 y_range = y_maze_max - y_maze_min - 2*INVPOS_Y_MARGIN - 1;
831 #ifdef DEBUG
832 if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN ||
833 (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE))
834 panic("inv_pos: maze is too small! (%d x %d)",
835 x_maze_max, y_maze_max);
836 #endif
837 inv_pos.x = inv_pos.y = 0; /*{occupied() => invocation_pos()}*/
838 do {
839 x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1);
840 y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1);
841 /* we don't want it to be too near the stairs, nor
842 to be on a spot that's already in use (wall|trap) */
843 } while (x == xupstair || y == yupstair || /*(direct line)*/
844 abs(x - xupstair) == abs(y - yupstair) ||
845 distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE ||
846 !SPACE_POS(levl[x][y].typ) || occupied(x, y));
847 inv_pos.x = x;
848 inv_pos.y = y;
850 /* spice this boring maze up - seven deadly sins :D --Amy */
851 mtmp = makemon(&mons[PM_LUST], 0, 0, NO_MM_FLAGS);
852 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
853 mtmp = makemon(&mons[PM_GLUTTONY], 0, 0, NO_MM_FLAGS);
854 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
855 mtmp = makemon(&mons[PM_ENVY], 0, 0, NO_MM_FLAGS);
856 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
857 mtmp = makemon(&mons[PM_PRIDE], 0, 0, NO_MM_FLAGS);
858 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
859 mtmp = makemon(&mons[PM_GREED], 0, 0, NO_MM_FLAGS);
860 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
861 mtmp = makemon(&mons[PM_SLOTH], 0, 0, NO_MM_FLAGS);
862 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
863 mtmp = makemon(&mons[PM_WRATH], 0, 0, NO_MM_FLAGS);
864 if (mtmp) (void) maketrap(mtmp->mx, mtmp->my, SIN_TRAP, 0, FALSE);
867 #undef INVPOS_X_MARGIN
868 #undef INVPOS_Y_MARGIN
869 #undef INVPOS_DISTANCE
870 #undef x_maze_min
871 #undef y_maze_min
874 /* place branch stair or portal */
875 place_branch(Is_branchlev(&u.uz), 0, 0);
877 #ifdef BIGSLEX
878 for(x = (rn2(4) ? rn1(12,24) : rn1(24, 48)); x; x--) {
879 #else
880 for(x = (rn2(4) ? rn1(8,16) : rn1(16, 32)); x; x--) {
881 #endif
882 if (timebasedlowerchance() || timebasedlowerchance() || timebasedlowerchance()) {
883 mazexy_all(&mm);
884 (void) mkobj_at(!rn2(25) ? GEM_CLASS : 0, mm.x, mm.y, TRUE, FALSE);
888 if (moves == 1) { /* some earlygame help... --Amy */
889 #ifdef BIGSLEX
890 for(x = (rn2(4) ? rn1(12,24) : rn1(24, 48)); x; x--) {
891 #else
892 for(x = (rn2(4) ? rn1(8,16) : rn1(16, 32)); x; x--) {
893 #endif
894 /* no timebasedlowerchance, this is not a mistake */
895 mazexy_all(&mm);
896 (void) mkobj_at(!rn2(25) ? GEM_CLASS : 0, mm.x, mm.y, TRUE, FALSE);
900 /* full-screen mazes are capable of boring the player's ass off, so there should be at least some loot --Amy */
901 #ifdef BIGSLEX
902 if (!rn2(5)) {
903 if (timebasedlowerchance()) {
904 mazexy_all(&mm);
905 (void) mksobj_at(LOOT_CHEST, mm.x, mm.y, TRUE, TRUE, FALSE);
908 if (!rn2(5)) {
909 if (timebasedlowerchance()) {
910 mazexy_all(&mm);
911 (void) mksobj_at(LOOT_CHEST, mm.x, mm.y, TRUE, TRUE, FALSE);
914 #endif
915 if (!rn2(5)) {
916 if (timebasedlowerchance()) {
917 mazexy_all(&mm);
918 (void) mksobj_at(LOOT_CHEST, mm.x, mm.y, TRUE, TRUE, FALSE);
922 #ifdef BIGSLEX
923 for (x = rn1(7,35); x; x--) {
924 #else
925 for (x = rn1(2,10); x; x--) {
926 #endif
927 mazexy_all(&mm);
928 char buf[BUFSZ];
929 const char *mesg = random_engraving(buf);
930 make_engr_at(mm.x, mm.y, mesg, 0L, (xchar)0);
932 for(x = rn1(10,2); x; x--) {
933 mazexy_all(&mm);
934 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE, FALSE);
936 if (!(iszapem && !(u.zapemescape)) && !(u.preversionmode && !u.preversionescape) && (depth(&u.uz) > depth(&medusa_level))) {
937 for (x = rn2(3); x; x--) {
938 mazexy_all(&mm);
939 if (!ishomicider) (void) makemon(minotaurvariant(), mm.x, mm.y, MM_MAYSLEEP);
940 else makerandomtrap_at(mm.x, mm.y, TRUE);
942 } /* cause they would be outta depth when mazes are generated at a shallow level --Amy */
943 #ifdef BIGSLEX
944 for(x = (rn2(2) ? rn1(70, 98) : rn2(4) ? rn1(18,24) : rn1(35, 49)); x; x--) {
945 #else
946 for(x = (rn2(2) ? rn1(20, 28) : rn2(4) ? rn1(5,7) : rn1(10, 14)); x; x--) {
947 #endif
948 mazexy_all(&mm);
949 if (!ishomicider) (void) makemon((struct permonst *) 0, mm.x, mm.y, MM_MAYSLEEP);
950 else makerandomtrap_at(mm.x, mm.y, TRUE);
952 for(x = rn1(6,7); x; x--) {
953 mazexy_all(&mm);
954 (void) mkgold(0L,mm.x,mm.y);
956 #ifdef BIGSLEX
957 for(x = (!rn2(6) ? rn1(84, 98) : rn2(4) ? rn1(21,24) : rn1(42, 49)); x; x--) {
958 #else
959 for(x = (!rn2(6) ? rn1(24, 28) : rn2(4) ? rn1(6,7) : rn1(12, 14)); x; x--) {
960 #endif
961 if (!(depth(&u.uz) == 1 && In_dod(&u.uz) && rn2(3)) && !(depth(&u.uz) == 2 && In_dod(&u.uz) && rn2(2)) ) {
962 mktrap(0,1,(struct mkroom *) 0, (coord*) 0, TRUE);
966 if (ishaxor) {
967 #ifdef BIGSLEX
968 for(x = (rn2(4) ? rn1(12,24) : rn1(24, 48)); x; x--) {
969 #else
970 for(x = (rn2(4) ? rn1(8,16) : rn1(16, 32)); x; x--) {
971 #endif
972 if (timebasedlowerchance() || timebasedlowerchance() || timebasedlowerchance()) {
973 mazexy_all(&mm);
974 (void) mkobj_at(!rn2(25) ? GEM_CLASS : 0, mm.x, mm.y, TRUE, FALSE);
977 #ifdef BIGSLEX
978 for (x = rn1(7,35); x; x--) {
979 #else
980 for (x = rn1(2,10); x; x--) {
981 #endif
982 mazexy_all(&mm);
983 char buf[BUFSZ];
984 const char *mesg = random_engraving(buf);
985 make_engr_at(mm.x, mm.y, mesg, 0L, (xchar)0);
987 for(x = rn1(10,2); x; x--) {
988 mazexy_all(&mm);
989 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE, FALSE);
991 if (!(iszapem && !(u.zapemescape)) && !(u.preversionmode && !u.preversionescape) && (depth(&u.uz) > depth(&medusa_level))) {
992 for (x = rn2(3); x; x--) {
993 mazexy_all(&mm);
994 if (!ishomicider) (void) makemon(minotaurvariant(), mm.x, mm.y, MM_MAYSLEEP);
995 else makerandomtrap_at(mm.x, mm.y, TRUE);
997 } /* cause they would be outta depth when mazes are generated at a shallow level --Amy */
998 #ifdef BIGSLEX
999 for(x = (rn2(2) ? rn1(70, 98) : rn2(4) ? rn1(18,24) : rn1(35, 49)); x; x--) {
1000 #else
1001 for(x = (rn2(2) ? rn1(20, 28) : rn2(4) ? rn1(5,7) : rn1(10, 14)); x; x--) {
1002 #endif
1003 mazexy_all(&mm);
1004 if (!ishomicider) (void) makemon((struct permonst *) 0, mm.x, mm.y, MM_MAYSLEEP);
1005 else makerandomtrap_at(mm.x, mm.y, TRUE);
1007 for(x = rn1(6,7); x; x--) {
1008 mazexy_all(&mm);
1009 (void) mkgold(0L,mm.x,mm.y);
1011 #ifdef BIGSLEX
1012 for(x = (!rn2(6) ? rn1(84, 98) : rn2(4) ? rn1(21,24) : rn1(42, 49)); x; x--) {
1013 #else
1014 for(x = (!rn2(6) ? rn1(24, 28) : rn2(4) ? rn1(6,7) : rn1(12, 14)); x; x--) {
1015 #endif
1016 if (!(depth(&u.uz) == 1 && In_dod(&u.uz) && rn2(3)) && !(depth(&u.uz) == 2 && In_dod(&u.uz) && rn2(2)) ) {
1017 mktrap(0,1,(struct mkroom *) 0, (coord*) 0, TRUE);
1022 } /* haxor check */
1024 /* chance to create Ludios portal, by Amy */
1025 if (In_dod(&u.uz)) {
1026 mazexy_all(&mm);
1027 if (isok(mm.x, mm.y)) mk_knox_portal(mm.x, mm.y);
1032 #ifdef MICRO
1033 /* Make the mazewalk iterative by faking a stack. This is needed to
1034 * ensure the mazewalk is successful in the limited stack space of
1035 * the program. This iterative version uses the minimum amount of stack
1036 * that is totally safe.
1038 void
1039 walkfrom(x,y)
1040 int x,y;
1042 #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */
1043 char mazex[CELLS + 1], mazey[CELLS + 1]; /* char's are OK */
1044 int q, a, dir, pos;
1045 int dirs[4];
1047 register int tryct = 0;
1048 register struct obj *otmpX;
1049 const char *str;
1051 int specialcorridor = 0;
1052 if (!rn2(iswarper ? 50 : 500)) specialcorridor = rnd(2);
1054 pos = 1;
1055 mazex[pos] = (char) x;
1056 mazey[pos] = (char) y;
1057 while (pos) {
1058 x = (int) mazex[pos];
1059 y = (int) mazey[pos];
1060 if(!IS_DOOR(levl[x][y].typ) && !specialcorridor) {
1061 /* might still be on edge of MAP, so don't overwrite */
1062 #ifndef WALLIFIED_MAZE
1063 levl[x][y].typ = CORR;
1064 #else
1065 levl[x][y].typ = ROOM;
1066 #endif
1067 levl[x][y].flags = 0;
1069 if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1070 levl[x][y].typ = THRONE;
1071 else if (!rn2(ishaxor ? 50000 : 100000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1072 levl[x][y].typ = PENTAGRAM;
1073 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1074 levl[x][y].typ = WELL;
1075 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1076 levl[x][y].typ = POISONEDWELL;
1077 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1078 levl[x][y].typ = WAGON;
1079 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1080 levl[x][y].typ = BURNINGWAGON;
1081 else if (!rn2(ishaxor ? 20000 : 40000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1082 levl[x][y].typ = WOODENTABLE;
1083 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1084 levl[x][y].typ = CARVEDBED;
1085 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1086 levl[x][y].typ = STRAWMATTRESS;
1087 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1088 levl[x][y].typ = FOUNTAIN;
1089 level.flags.nfountains++;
1091 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1092 levl[x][y].typ = SINK;
1093 level.flags.nsinks++;
1095 else if (!rn2(ishaxor ? 5000 : 10000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1096 levl[x][y].typ = TOILET;
1097 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1098 levl[x][y].typ = GRAVE;
1099 str = random_epitaph();
1100 del_engr_at(x, y);
1101 make_engr_at(x, y, str, 0L, HEADSTONE);
1103 if (!rn2(3)) (void) mkgold(0L, x, y);
1104 for (tryct = rn2(5); tryct; tryct--) {
1105 if (timebasedlowerchance()) {
1106 otmpX = mkobj(RANDOM_CLASS, TRUE, FALSE);
1107 if (!otmpX) return;
1108 curse(otmpX);
1109 otmpX->ox = x;
1110 otmpX->oy = y;
1111 add_to_buried(otmpX);
1115 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1116 levl[x][y].typ = ALTAR;
1117 if (rn2(10)) levl[x][y].altarmask = Align2amask( A_NONE );
1118 else switch (rnd(3)) {
1119 case 1: levl[x][y].altarmask = Align2amask( A_LAWFUL ); break;
1120 case 2: levl[x][y].altarmask = Align2amask( A_NEUTRAL ); break;
1121 case 3: levl[x][y].altarmask = Align2amask( A_CHAOTIC ); break;
1124 if (!rn2(25)) {
1125 register struct obj *altarwater;
1126 altarwater = mksobj_at(POT_WATER, x, y, FALSE, FALSE, FALSE);
1127 if (altarwater) {
1128 if (Amask2align(levl[x][y].altarmask) == A_NONE && !rn2(5)) curse(altarwater);
1129 else bless(altarwater);
1134 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1135 levl[x][y].typ = TREE;
1136 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1137 levl[x][y].typ = MOAT;
1138 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1139 levl[x][y].typ = LAVAPOOL;
1140 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1141 levl[x][y].typ = ICE;
1142 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1143 levl[x][y].typ = CLOUD;
1144 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1145 levl[x][y].typ = GRAVEWALL;
1146 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1147 levl[x][y].typ = SNOW;
1148 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1149 levl[x][y].typ = ASH;
1150 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1151 levl[x][y].typ = SAND;
1152 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1153 levl[x][y].typ = PAVEDFLOOR;
1154 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1155 levl[x][y].typ = HIGHWAY;
1156 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1157 levl[x][y].typ = GRASSLAND;
1158 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1159 levl[x][y].typ = NETHERMIST;
1160 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1161 levl[x][y].typ = STALACTITE;
1162 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1163 levl[x][y].typ = CRYPTFLOOR;
1164 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1165 levl[x][y].typ = BUBBLES;
1166 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1167 levl[x][y].typ = RAINCLOUD;
1168 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1169 levl[x][y].typ = TUNNELWALL;
1170 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1171 levl[x][y].typ = FARMLAND;
1172 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1173 levl[x][y].typ = MOUNTAIN;
1174 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1175 levl[x][y].typ = WATERTUNNEL;
1176 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1177 levl[x][y].typ = CRYSTALWATER;
1178 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1179 levl[x][y].typ = MOORLAND;
1180 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1181 levl[x][y].typ = URINELAKE;
1182 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1183 levl[x][y].typ = SHIFTINGSAND;
1184 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1185 levl[x][y].typ = STYXRIVER;
1188 if(!IS_DOOR(levl[x][y].typ) && specialcorridor) {
1190 levl[x][y].typ = walkableterrain();
1191 levl[x][y].flags = 0;
1194 q = 0;
1195 for (a = 0; a < 4; a++)
1196 if(okay(x, y, a)) dirs[q++]= a;
1197 if (!q)
1198 pos--;
1199 else {
1200 dir = dirs[rn2(q)];
1201 move(&x, &y, dir);
1203 if (!specialcorridor) {
1204 #ifndef WALLIFIED_MAZE
1205 levl[x][y].typ = CORR;
1206 #else
1207 levl[x][y].typ = ROOM;
1208 #endif
1210 if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1211 levl[x][y].typ = THRONE;
1212 else if (!rn2(ishaxor ? 50000 : 100000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1213 levl[x][y].typ = PENTAGRAM;
1214 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1215 levl[x][y].typ = WELL;
1216 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1217 levl[x][y].typ = POISONEDWELL;
1218 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1219 levl[x][y].typ = WAGON;
1220 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1221 levl[x][y].typ = BURNINGWAGON;
1222 else if (!rn2(ishaxor ? 20000 : 40000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1223 levl[x][y].typ = WOODENTABLE;
1224 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1225 levl[x][y].typ = CARVEDBED;
1226 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1227 levl[x][y].typ = STRAWMATTRESS;
1228 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))){
1229 levl[x][y].typ = FOUNTAIN;
1230 level.flags.nfountains++;
1232 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1233 levl[x][y].typ = SINK;
1234 level.flags.nsinks++;
1236 else if (!rn2(ishaxor ? 5000 : 10000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1237 levl[x][y].typ = TOILET;
1238 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1239 levl[x][y].typ = GRAVE;
1240 str = random_epitaph();
1241 del_engr_at(x, y);
1242 make_engr_at(x, y, str, 0L, HEADSTONE);
1244 if (!rn2(3)) (void) mkgold(0L, x, y);
1245 for (tryct = rn2(5); tryct; tryct--) {
1246 if (timebasedlowerchance()) {
1247 otmpX = mkobj(RANDOM_CLASS, TRUE, FALSE);
1248 if (!otmpX) return;
1249 curse(otmpX);
1250 otmpX->ox = x;
1251 otmpX->oy = y;
1252 add_to_buried(otmpX);
1256 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1257 levl[x][y].typ = ALTAR;
1258 if (rn2(10)) levl[x][y].altarmask = Align2amask( A_NONE );
1259 else switch (rnd(3)) {
1260 case 1: levl[x][y].altarmask = Align2amask( A_LAWFUL ); break;
1261 case 2: levl[x][y].altarmask = Align2amask( A_NEUTRAL ); break;
1262 case 3: levl[x][y].altarmask = Align2amask( A_CHAOTIC ); break;
1265 if (!rn2(25)) {
1266 register struct obj *altarwater;
1267 altarwater = mksobj_at(POT_WATER, x, y, FALSE, FALSE, FALSE);
1268 if (altarwater) {
1269 if (Amask2align(levl[x][y].altarmask) == A_NONE && !rn2(5)) curse(altarwater);
1270 else bless(altarwater);
1275 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1276 levl[x][y].typ = TREE;
1277 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1278 levl[x][y].typ = MOAT;
1279 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1280 levl[x][y].typ = LAVAPOOL;
1281 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1282 levl[x][y].typ = ICE;
1283 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1284 levl[x][y].typ = CLOUD;
1285 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1286 levl[x][y].typ = GRAVEWALL;
1287 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1288 levl[x][y].typ = SNOW;
1289 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1290 levl[x][y].typ = ASH;
1291 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1292 levl[x][y].typ = SAND;
1293 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1294 levl[x][y].typ = PAVEDFLOOR;
1295 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1296 levl[x][y].typ = HIGHWAY;
1297 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1298 levl[x][y].typ = GRASSLAND;
1299 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1300 levl[x][y].typ = NETHERMIST;
1301 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1302 levl[x][y].typ = STALACTITE;
1303 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1304 levl[x][y].typ = CRYPTFLOOR;
1305 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1306 levl[x][y].typ = BUBBLES;
1307 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1308 levl[x][y].typ = RAINCLOUD;
1309 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1310 levl[x][y].typ = TUNNELWALL;
1311 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1312 levl[x][y].typ = FARMLAND;
1313 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1314 levl[x][y].typ = MOUNTAIN;
1315 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1316 levl[x][y].typ = WATERTUNNEL;
1317 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1318 levl[x][y].typ = CRYSTALWATER;
1319 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1320 levl[x][y].typ = MOORLAND;
1321 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1322 levl[x][y].typ = URINELAKE;
1323 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1324 levl[x][y].typ = SHIFTINGSAND;
1325 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1326 levl[x][y].typ = STYXRIVER;
1329 else levl[x][y].typ = walkableterrain();
1331 move(&x, &y, dir);
1332 pos++;
1333 if (pos > CELLS)
1334 panic("Overflow in walkfrom");
1335 mazex[pos] = (char) x;
1336 mazey[pos] = (char) y;
1340 #else
1342 void
1343 walkfrom(x,y)
1344 int x,y;
1346 register int q,a,dir;
1347 int dirs[4];
1349 register int tryct = 0;
1350 register struct obj *otmpX;
1351 const char *str;
1353 int specialcorridor = 0;
1354 if (!rn2(iswarper ? 50 : 500)) specialcorridor = rnd(2);
1356 if(!IS_DOOR(levl[x][y].typ) && !specialcorridor) {
1357 /* might still be on edge of MAP, so don't overwrite */
1358 #ifndef WALLIFIED_MAZE
1359 levl[x][y].typ = CORR;
1360 #else
1361 levl[x][y].typ = ROOM;
1362 #endif
1363 levl[x][y].flags = 0;
1365 if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1366 levl[x][y].typ = THRONE;
1367 else if (!rn2(ishaxor ? 50000 : 100000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1368 levl[x][y].typ = PENTAGRAM;
1369 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1370 levl[x][y].typ = WELL;
1371 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1372 levl[x][y].typ = POISONEDWELL;
1373 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1374 levl[x][y].typ = WAGON;
1375 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1376 levl[x][y].typ = BURNINGWAGON;
1377 else if (!rn2(ishaxor ? 20000 : 40000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1378 levl[x][y].typ = WOODENTABLE;
1379 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1380 levl[x][y].typ = CARVEDBED;
1381 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1382 levl[x][y].typ = STRAWMATTRESS;
1383 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1384 levl[x][y].typ = FOUNTAIN;
1385 level.flags.nfountains++;
1387 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1388 levl[x][y].typ = SINK;
1389 level.flags.nsinks++;
1391 else if (!rn2(ishaxor ? 5000 : 10000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1392 levl[x][y].typ = TOILET;
1393 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1394 levl[x][y].typ = GRAVE;
1395 str = random_epitaph();
1396 del_engr_at(x, y);
1397 make_engr_at(x, y, str, 0L, HEADSTONE);
1399 if (!rn2(3)) (void) mkgold(0L, x, y);
1400 for (tryct = rn2(5); tryct; tryct--) {
1401 if (timebasedlowerchance()) {
1402 otmpX = mkobj(RANDOM_CLASS, TRUE, FALSE);
1403 if (!otmpX) return;
1404 curse(otmpX);
1405 otmpX->ox = x;
1406 otmpX->oy = y;
1407 add_to_buried(otmpX);
1411 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1412 levl[x][y].typ = ALTAR;
1413 if (rn2(10)) levl[x][y].altarmask = Align2amask( A_NONE );
1414 else switch (rnd(3)) {
1415 case 1: levl[x][y].altarmask = Align2amask( A_LAWFUL ); break;
1416 case 2: levl[x][y].altarmask = Align2amask( A_NEUTRAL ); break;
1417 case 3: levl[x][y].altarmask = Align2amask( A_CHAOTIC ); break;
1420 if (!rn2(25)) {
1421 register struct obj *altarwater;
1422 altarwater = mksobj_at(POT_WATER, x, y, FALSE, FALSE, FALSE);
1423 if (altarwater) {
1424 if (Amask2align(levl[x][y].altarmask) == A_NONE && !rn2(5)) curse(altarwater);
1425 else bless(altarwater);
1430 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1431 levl[x][y].typ = TREE;
1432 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1433 levl[x][y].typ = MOAT;
1434 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1435 levl[x][y].typ = LAVAPOOL;
1436 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1437 levl[x][y].typ = ICE;
1438 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1439 levl[x][y].typ = CLOUD;
1440 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1441 levl[x][y].typ = GRAVEWALL;
1442 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1443 levl[x][y].typ = SNOW;
1444 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1445 levl[x][y].typ = ASH;
1446 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1447 levl[x][y].typ = SAND;
1448 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1449 levl[x][y].typ = PAVEDFLOOR;
1450 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1451 levl[x][y].typ = HIGHWAY;
1452 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1453 levl[x][y].typ = GRASSLAND;
1454 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1455 levl[x][y].typ = NETHERMIST;
1456 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1457 levl[x][y].typ = STALACTITE;
1458 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1459 levl[x][y].typ = CRYPTFLOOR;
1460 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1461 levl[x][y].typ = BUBBLES;
1462 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1463 levl[x][y].typ = RAINCLOUD;
1464 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1465 levl[x][y].typ = TUNNELWALL;
1466 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1467 levl[x][y].typ = FARMLAND;
1468 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1469 levl[x][y].typ = MOUNTAIN;
1470 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1471 levl[x][y].typ = WATERTUNNEL;
1472 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1473 levl[x][y].typ = CRYSTALWATER;
1474 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1475 levl[x][y].typ = MOORLAND;
1476 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1477 levl[x][y].typ = URINELAKE;
1478 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1479 levl[x][y].typ = SHIFTINGSAND;
1480 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1481 levl[x][y].typ = STYXRIVER;
1484 if(!IS_DOOR(levl[x][y].typ) && specialcorridor) {
1486 levl[x][y].typ = walkableterrain();
1487 levl[x][y].flags = 0;
1490 while(1) {
1491 q = 0;
1492 for(a = 0; a < 4; a++)
1493 if(okay(x,y,a)) dirs[q++]= a;
1494 if(!q) return;
1495 dir = dirs[rn2(q)];
1496 move(&x,&y,dir);
1497 if (!specialcorridor) {
1498 #ifndef WALLIFIED_MAZE
1499 levl[x][y].typ = CORR;
1500 #else
1501 levl[x][y].typ = ROOM;
1502 #endif
1503 if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1504 levl[x][y].typ = THRONE;
1505 else if (!rn2(ishaxor ? 50000 : 100000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1506 levl[x][y].typ = PENTAGRAM;
1507 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1508 levl[x][y].typ = WELL;
1509 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1510 levl[x][y].typ = POISONEDWELL;
1511 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1512 levl[x][y].typ = WAGON;
1513 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1514 levl[x][y].typ = BURNINGWAGON;
1515 else if (!rn2(ishaxor ? 20000 : 40000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1516 levl[x][y].typ = WOODENTABLE;
1517 else if (!rn2(ishaxor ? 25000 : 50000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1518 levl[x][y].typ = CARVEDBED;
1519 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1520 levl[x][y].typ = STRAWMATTRESS;
1521 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1522 levl[x][y].typ = FOUNTAIN;
1523 level.flags.nfountains++;
1525 else if (!rn2(ishaxor ? 2500 : 5000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1526 levl[x][y].typ = SINK;
1527 level.flags.nsinks++;
1529 else if (!rn2(ishaxor ? 5000 : 10000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1530 levl[x][y].typ = TOILET;
1531 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1532 levl[x][y].typ = GRAVE;
1533 str = random_epitaph();
1534 del_engr_at(x, y);
1535 make_engr_at(x, y, str, 0L, HEADSTONE);
1537 if (!rn2(3)) (void) mkgold(0L, x, y);
1538 for (tryct = rn2(5); tryct; tryct--) {
1539 if (timebasedlowerchance()) {
1540 otmpX = mkobj(RANDOM_CLASS, TRUE, FALSE);
1541 if (!otmpX) return;
1542 curse(otmpX);
1543 otmpX->ox = x;
1544 otmpX->oy = y;
1545 add_to_buried(otmpX);
1549 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM))) {
1550 levl[x][y].typ = ALTAR;
1551 if (rn2(10)) levl[x][y].altarmask = Align2amask( A_NONE );
1552 else switch (rnd(3)) {
1553 case 1: levl[x][y].altarmask = Align2amask( A_LAWFUL ); break;
1554 case 2: levl[x][y].altarmask = Align2amask( A_NEUTRAL ); break;
1555 case 3: levl[x][y].altarmask = Align2amask( A_CHAOTIC ); break;
1558 if (!rn2(25)) {
1559 register struct obj *altarwater;
1560 altarwater = mksobj_at(POT_WATER, x, y, FALSE, FALSE, FALSE);
1561 if (altarwater) {
1562 if (Amask2align(levl[x][y].altarmask) == A_NONE && !rn2(5)) curse(altarwater);
1563 else bless(altarwater);
1568 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1569 levl[x][y].typ = TREE;
1570 else if (!rn2(ishaxor ? 1000 : 2000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1571 levl[x][y].typ = MOAT;
1572 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1573 levl[x][y].typ = LAVAPOOL;
1574 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1575 levl[x][y].typ = ICE;
1576 else if (!rn2(ishaxor ? 500 : 1000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1577 levl[x][y].typ = CLOUD;
1578 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1579 levl[x][y].typ = GRAVEWALL;
1580 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1581 levl[x][y].typ = SNOW;
1582 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1583 levl[x][y].typ = ASH;
1584 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1585 levl[x][y].typ = SAND;
1586 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1587 levl[x][y].typ = PAVEDFLOOR;
1588 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1589 levl[x][y].typ = HIGHWAY;
1590 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1591 levl[x][y].typ = GRASSLAND;
1592 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1593 levl[x][y].typ = NETHERMIST;
1594 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1595 levl[x][y].typ = STALACTITE;
1596 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1597 levl[x][y].typ = CRYPTFLOOR;
1598 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1599 levl[x][y].typ = BUBBLES;
1600 else if (!rn2(ishaxor ? 2000 : 4000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1601 levl[x][y].typ = RAINCLOUD;
1602 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1603 levl[x][y].typ = TUNNELWALL;
1604 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1605 levl[x][y].typ = FARMLAND;
1606 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1607 levl[x][y].typ = MOUNTAIN;
1608 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1609 levl[x][y].typ = WATERTUNNEL;
1610 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1611 levl[x][y].typ = CRYSTALWATER;
1612 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1613 levl[x][y].typ = MOORLAND;
1614 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1615 levl[x][y].typ = URINELAKE;
1616 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1617 levl[x][y].typ = SHIFTINGSAND;
1618 else if (!rn2(ishaxor ? 10000 : 20000) && ((levl[x][y].typ == CORR) || (levl[x][y].typ == ROOM)))
1619 levl[x][y].typ = STYXRIVER;
1622 else levl[x][y].typ = walkableterrain();
1623 move(&x,&y,dir);
1624 walkfrom(x,y);
1627 #endif /* MICRO */
1629 STATIC_OVL void
1630 move(x,y,dir)
1631 register int *x, *y;
1632 register int dir;
1634 switch(dir){
1635 case 0: --(*y); break;
1636 case 1: (*x)++; break;
1637 case 2: (*y)++; break;
1638 case 3: --(*x); break;
1639 default: panic("move: bad direction");
1643 void
1644 mazexy(cc) /* find random point in generated corridors,
1645 so we don't create items in moats, bunkers, or walls */
1646 coord *cc;
1648 int cpt=0;
1650 do {
1651 cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
1652 cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
1653 cpt++;
1654 } while (cpt < 100 && levl[cc->x][cc->y].typ !=
1655 #ifdef WALLIFIED_MAZE
1656 ROOM
1657 #else
1658 CORR
1659 #endif
1661 if (cpt >= 100) {
1662 register int x, y;
1663 /* last try */
1664 for (x = 0; x < (x_maze_max>>1) - 1; x++)
1665 for (y = 0; y < (y_maze_max>>1) - 1; y++) {
1666 cc->x = 3 + 2 * x;
1667 cc->y = 3 + 2 * y;
1668 if (levl[cc->x][cc->y].typ ==
1669 #ifdef WALLIFIED_MAZE
1670 ROOM
1671 #else
1672 CORR
1673 #endif
1674 ) return;
1677 for (x = 0; x < (x_maze_max>>1) - 1; x++)
1678 for (y = 0; y < (y_maze_max>>1) - 1; y++) {
1679 cc->x = 3 + 2 * x;
1680 cc->y = 3 + 2 * y;
1681 if ((levl[cc->x][cc->y].typ == ROOM) || (levl[cc->x][cc->y].typ == CORR) || (levl[cc->x][cc->y].typ == CLOUD) || (levl[cc->x][cc->y].typ == ICE) || (levl[cc->x][cc->y].typ == SNOW) || (levl[cc->x][cc->y].typ == ASH) || (levl[cc->x][cc->y].typ == SAND) || (levl[cc->x][cc->y].typ == PAVEDFLOOR) || (levl[cc->x][cc->y].typ == HIGHWAY) || (levl[cc->x][cc->y].typ == GRASSLAND) || (levl[cc->x][cc->y].typ == NETHERMIST) || (levl[cc->x][cc->y].typ == STALACTITE) || (levl[cc->x][cc->y].typ == CRYPTFLOOR) || (levl[cc->x][cc->y].typ == BUBBLES) || (levl[cc->x][cc->y].typ == RAINCLOUD)) return;
1684 for (x = 0; x < (x_maze_max) - 1; x++)
1685 for (y = 0; y < (y_maze_max) - 1; y++) {
1686 cc->x = 3 + x;
1687 cc->y = 3 + y;
1688 if ((levl[cc->x][cc->y].typ >= ROCKWALL && levl[cc->x][cc->y].typ <= URINELAKE) || (levl[cc->x][cc->y].typ >= SHIFTINGSAND && levl[cc->x][cc->y].typ <= ROOM) || (levl[cc->x][cc->y].typ >= ICE && levl[cc->x][cc->y].typ <= CRYPTFLOOR) || (levl[cc->x][cc->y].typ >= AIR && levl[cc->x][cc->y].typ <= RAINCLOUD) ) return;
1691 panic("mazexy: can't find a place!");
1693 return;
1696 void
1697 mazexy_all(cc) /* mazexy() only returns "even-numbered" squares... --Amy */
1698 coord *cc;
1700 int cpt=0;
1702 do {
1703 cc->x = 3 + rn2((x_maze_max) - 1);
1704 cc->y = 3 + rn2((y_maze_max) - 1);
1705 cpt++;
1706 } while (cpt < 100 && levl[cc->x][cc->y].typ !=
1707 #ifdef WALLIFIED_MAZE
1708 ROOM
1709 #else
1710 CORR
1711 #endif
1713 if (cpt >= 100) {
1714 register int x, y;
1715 /* last try */
1716 for (x = 0; x < (x_maze_max) - 1; x++)
1717 for (y = 0; y < (y_maze_max) - 1; y++) {
1718 cc->x = 3 + x;
1719 cc->y = 3 + y;
1720 if (levl[cc->x][cc->y].typ ==
1721 #ifdef WALLIFIED_MAZE
1722 ROOM
1723 #else
1724 CORR
1725 #endif
1726 ) return;
1729 for (x = 0; x < (x_maze_max) - 1; x++)
1730 for (y = 0; y < (y_maze_max) - 1; y++) {
1731 cc->x = 3 + x;
1732 cc->y = 3 + y;
1733 if ((levl[cc->x][cc->y].typ == ROOM) || (levl[cc->x][cc->y].typ == CORR) || (levl[cc->x][cc->y].typ == CLOUD) || (levl[cc->x][cc->y].typ == ICE) || (levl[cc->x][cc->y].typ == SNOW) || (levl[cc->x][cc->y].typ == ASH) || (levl[cc->x][cc->y].typ == SAND) || (levl[cc->x][cc->y].typ == PAVEDFLOOR) || (levl[cc->x][cc->y].typ == HIGHWAY) || (levl[cc->x][cc->y].typ == GRASSLAND) || (levl[cc->x][cc->y].typ == NETHERMIST) || (levl[cc->x][cc->y].typ == STALACTITE) || (levl[cc->x][cc->y].typ == CRYPTFLOOR) || (levl[cc->x][cc->y].typ == BUBBLES) || (levl[cc->x][cc->y].typ == RAINCLOUD)) return;
1736 for (x = 0; x < (x_maze_max) - 1; x++)
1737 for (y = 0; y < (y_maze_max) - 1; y++) {
1738 cc->x = 3 + x;
1739 cc->y = 3 + y;
1740 if ((levl[cc->x][cc->y].typ >= ROCKWALL && levl[cc->x][cc->y].typ <= URINELAKE) || (levl[cc->x][cc->y].typ >= SHIFTINGSAND && levl[cc->x][cc->y].typ <= ROOM) || (levl[cc->x][cc->y].typ >= ICE && levl[cc->x][cc->y].typ <= CRYPTFLOOR) || (levl[cc->x][cc->y].typ >= AIR && levl[cc->x][cc->y].typ <= RAINCLOUD) ) return;
1743 panic("mazexy_all: can't find a place!");
1745 return;
1748 void
1749 bound_digging()
1750 /* put a non-diggable boundary around the initial portion of a level map.
1751 * assumes that no level will initially put things beyond the isok() range.
1753 * we can't bound unconditionally on the last line with something in it,
1754 * because that something might be a niche which was already reachable,
1755 * so the boundary would be breached
1757 * we can't bound unconditionally on one beyond the last line, because
1758 * that provides a window of abuse for WALLIFIED_MAZE special levels
1761 register int x,y;
1762 register int quasarchance;
1763 register unsigned typ;
1764 register struct rm *lev;
1765 boolean found, nonwall;
1766 int xmin,xmax,ymin,ymax;
1768 quasarchance = 3 + rn2(5);
1770 for (x = 0; x < COLNO; x++)
1771 for (y = 0; y < ROWNO; y++) {
1772 if (!rn2(quasarchance)) levl[x][y].wall_info |= W_QUASAROK;
1773 levl[x][y].nofunwall = rn2(43);
1776 if(Is_earthlevel(&u.uz)) return; /* everything diggable here */
1778 found = nonwall = FALSE;
1779 for(xmin=0; !found; xmin++) {
1780 lev = &levl[xmin][0];
1781 for(y=0; y<=ROWNO-1; y++, lev++) {
1782 typ = lev->typ;
1783 if(typ != STONE) {
1784 found = TRUE;
1785 if(!IS_WALL(typ)) nonwall = TRUE;
1789 xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
1790 if (xmin < 0) xmin = 0;
1792 found = nonwall = FALSE;
1793 for(xmax=COLNO-1; !found; xmax--) {
1794 lev = &levl[xmax][0];
1795 for(y=0; y<=ROWNO-1; y++, lev++) {
1796 typ = lev->typ;
1797 if(typ != STONE) {
1798 found = TRUE;
1799 if(!IS_WALL(typ)) nonwall = TRUE;
1803 xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
1804 if (xmax >= COLNO) xmax = COLNO-1;
1806 found = nonwall = FALSE;
1807 for(ymin=0; !found; ymin++) {
1808 lev = &levl[xmin][ymin];
1809 for(x=xmin; x<=xmax; x++, lev += ROWNO) {
1810 typ = lev->typ;
1811 if(typ != STONE) {
1812 found = TRUE;
1813 if(!IS_WALL(typ)) nonwall = TRUE;
1817 ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
1819 found = nonwall = FALSE;
1820 for(ymax=ROWNO-1; !found; ymax--) {
1821 lev = &levl[xmin][ymax];
1822 for(x=xmin; x<=xmax; x++, lev += ROWNO) {
1823 typ = lev->typ;
1824 if(typ != STONE) {
1825 found = TRUE;
1826 if(!IS_WALL(typ)) nonwall = TRUE;
1830 ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
1832 for (x = 0; x < COLNO; x++)
1833 for (y = 0; y < ROWNO; y++)
1834 if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) {
1835 #ifdef DCC30_BUG
1836 lev = &levl[x][y];
1837 lev->wall_info |= W_NONDIGGABLE;
1838 #else
1839 levl[x][y].wall_info |= W_NONDIGGABLE;
1840 #endif
1844 void
1845 mkportal(x, y, todnum, todlevel)
1846 register xchar x, y, todnum, todlevel;
1848 /* a portal "trap" must be matched by a */
1849 /* portal in the destination dungeon/dlevel */
1850 register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL, 0, FALSE);
1852 if (!ttmp) {
1853 impossible("portal on top of portal??");
1854 return;
1856 #ifdef DEBUG
1857 pline("mkportal: at (%d,%d), to %s, level %d",
1858 x, y, dungeons[todnum].dname, todlevel);
1859 #endif
1860 ttmp->dst.dnum = todnum;
1861 ttmp->dst.dlevel = todlevel;
1862 return;
1866 * Special waterlevel stuff in endgame (TH).
1868 * Some of these functions would probably logically belong to some
1869 * other source files, but they are all so nicely encapsulated here.
1872 /* to ease the work of debuggers at this stage */
1873 #define register
1875 #define CONS_OBJ 0
1876 #define CONS_MON 1
1877 #define CONS_HERO 2
1878 #define CONS_TRAP 3
1880 static struct bubble *bbubbles, *ebubbles;
1882 static struct trap *wportal;
1883 static int xmin, ymin, xmax, ymax; /* level boundaries */
1884 /* bubble movement boundaries */
1885 #define bxmin (xmin + 1)
1886 #define bymin (ymin + 1)
1887 #define bxmax (xmax - 1)
1888 #define bymax (ymax - 1)
1890 STATIC_DCL void set_wportal(void);
1891 STATIC_DCL void mk_bubble(int,int,int);
1892 STATIC_DCL void mv_bubble(struct bubble *,int,int,BOOLEAN_P);
1894 void
1895 movebubbles()
1897 static boolean up;
1898 register struct bubble *b;
1899 register int x, y, i, j;
1900 struct trap *btrap;
1901 static const struct rm water_pos =
1902 #ifdef DISPLAY_LAYERS
1903 { S_water, 0, 0, 0, 0, 0,
1904 #else
1905 { cmap_to_glyph(S_water),
1906 #endif
1907 WATER, 0, 0, 0, 0, 0, 0, 0 };
1909 /* set up the portal the first time bubbles are moved */
1910 if (!wportal) set_wportal();
1912 vision_recalc(2);
1913 /* fix from 3.4.3: keep attached ball&chain separate from bubble objects, otherwise panic! */
1914 if (Punished) unplacebc();
1917 * Pick up everything inside of a bubble then fill all bubble
1918 * locations.
1921 for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
1922 if (b->cons) panic("movebubbles: cons != null");
1923 for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
1924 for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
1925 if (b->bm[j + 2] & (1 << i)) {
1926 if (!isok(x,y)) {
1927 impossible("movebubbles: bad pos (%d,%d)", x,y);
1928 continue;
1931 /* pick up objects, monsters, hero, and traps */
1932 if (OBJ_AT(x,y)) {
1933 struct obj *olist = (struct obj *) 0, *otmp;
1934 struct container *cons = (struct container *)
1935 alloc(sizeof(struct container));
1937 while ((otmp = level.objects[x][y]) != 0) {
1938 remove_object(otmp);
1939 otmp->ox = otmp->oy = 0;
1940 otmp->nexthere = olist;
1941 olist = otmp;
1944 cons->x = x;
1945 cons->y = y;
1946 cons->what = CONS_OBJ;
1947 cons->list = (void *) olist;
1948 cons->next = b->cons;
1949 b->cons = cons;
1951 if (MON_AT(x,y)) {
1952 struct monst *mon = m_at(x,y);
1953 struct container *cons = (struct container *)
1954 alloc(sizeof(struct container));
1956 cons->x = x;
1957 cons->y = y;
1958 cons->what = CONS_MON;
1959 cons->list = (void *) mon;
1961 cons->next = b->cons;
1962 b->cons = cons;
1964 if(mon->wormno)
1965 remove_worm(mon);
1966 else
1967 remove_monster(x, y);
1969 newsym(x,y); /* clean up old position */
1970 mon->mx = mon->my = 0;
1972 if (!u.uswallow && x == u.ux && y == u.uy) {
1973 struct container *cons = (struct container *)
1974 alloc(sizeof(struct container));
1976 cons->x = x;
1977 cons->y = y;
1978 cons->what = CONS_HERO;
1979 cons->list = (void *) 0;
1981 cons->next = b->cons;
1982 b->cons = cons;
1984 if ((btrap = t_at(x,y)) != 0) {
1985 struct container *cons = (struct container *)
1986 alloc(sizeof(struct container));
1988 cons->x = x;
1989 cons->y = y;
1990 cons->what = CONS_TRAP;
1991 cons->list = (void *) btrap;
1993 cons->next = b->cons;
1994 b->cons = cons;
1997 levl[x][y] = water_pos;
1998 block_point(x,y);
2003 * Every second time traverse down. This is because otherwise
2004 * all the junk that changes owners when bubbles overlap
2005 * would eventually end up in the last bubble in the chain.
2008 up = !up;
2009 for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
2010 register int rx = rn2(3), ry = rn2(3);
2012 mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)),
2013 b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)),
2014 FALSE);
2017 /* put attached ball&chain back */
2018 if (Punished) placebc();
2019 vision_full_recalc = 1;
2022 /* when moving in water, possibly (1 in 3) alter the intended destination */
2023 void
2024 water_friction()
2026 register int x, y, dx, dy;
2027 register boolean eff = FALSE;
2029 if (Race_if(PM_SEA_ELF)) return; /* idea by Elronnd: they are at home in the sea, and therefore unaffected */
2030 if (tech_inuse(T_SILENT_OCEAN)) return; /* if the ocean is silent, it means there are no currents */
2031 if (uarmh && uarmh->oartifact == ART_AIR_ON_HOLD) return;
2033 if (Swimming && rn2(StrongSwimming ? 20 : 4))
2034 return; /* natural swimmers have advantage */
2036 if (u.dx && !rn2(!u.dy ? 3 : 6)) { /* 1/3 chance or half that */
2037 /* cancel delta x and choose an arbitrary delta y value */
2038 x = u.ux;
2039 do {
2040 dy = rn2(3) - 1; /* -1, 0, 1 */
2041 y = u.uy + dy;
2042 } while (dy && (!isok(x,y) || (!is_waterypool(x,y) && !is_watertunnel(x,y) ) ));
2043 u.dx = 0;
2044 u.dy = dy;
2045 eff = TRUE;
2046 } else if (u.dy && !rn2(!u.dx ? 3 : 5)) { /* 1/3 or 1/5*(5/6) */
2047 /* cancel delta y and choose an arbitrary delta x value */
2048 y = u.uy;
2049 do {
2050 dx = rn2(3) - 1; /* -1 .. 1 */
2051 x = u.ux + dx;
2052 } while (dx && (!isok(x,y) || (!is_waterypool(x,y) && !is_watertunnel(x,y) ) ));
2053 u.dy = 0;
2054 u.dx = dx;
2055 eff = TRUE;
2057 if (eff) pline("Water turbulence affects your movements.");
2060 void
2061 save_waterlevel(fd, mode)
2062 int fd, mode;
2064 register struct bubble *b;
2066 if (!Is_waterlevel(&u.uz)) return;
2068 if (perform_bwrite(mode)) {
2069 int n = 0;
2070 for (b = bbubbles; b; b = b->next) ++n;
2071 bwrite(fd, (void *)&n, sizeof (int));
2072 bwrite(fd, (void *)&xmin, sizeof (int));
2073 bwrite(fd, (void *)&ymin, sizeof (int));
2074 bwrite(fd, (void *)&xmax, sizeof (int));
2075 bwrite(fd, (void *)&ymax, sizeof (int));
2076 for (b = bbubbles; b; b = b->next)
2077 bwrite(fd, (void *)b, sizeof (struct bubble));
2079 if (release_data(mode))
2080 unsetup_waterlevel();
2083 void
2084 restore_waterlevel(fd)
2085 register int fd;
2087 register struct bubble *b = (struct bubble *)0, *btmp;
2088 register int i;
2089 int n;
2091 if (!Is_waterlevel(&u.uz)) return;
2093 set_wportal();
2094 mread(fd,(void *)&n,sizeof(int));
2095 mread(fd,(void *)&xmin,sizeof(int));
2096 mread(fd,(void *)&ymin,sizeof(int));
2097 mread(fd,(void *)&xmax,sizeof(int));
2098 mread(fd,(void *)&ymax,sizeof(int));
2100 if (n > 0) {
2101 for (i = 0; i < n; i++) {
2102 btmp = b;
2103 b = (struct bubble *)alloc(sizeof(struct bubble));
2104 mread(fd,(void *)b,sizeof(struct bubble));
2105 if (bbubbles) {
2106 btmp->next = b;
2107 b->prev = btmp;
2108 } else {
2109 bbubbles = b;
2110 b->prev = (struct bubble *)0;
2112 mv_bubble(b,0,0,TRUE);
2114 ebubbles = b;
2115 b->next = (struct bubble *)0;
2117 was_waterlevel = TRUE;
2120 const char *waterbody_name(x, y)
2121 xchar x,y;
2123 register struct rm *lev;
2124 schar ltyp;
2126 if (!isok(x,y))
2127 return "drink"; /* should never happen */
2128 lev = &levl[x][y];
2129 ltyp = lev->typ;
2131 if (is_lava(x,y))
2132 return "lava";
2133 else if (ltyp == ICE ||
2134 (ltyp == DRAWBRIDGE_UP &&
2135 (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE))
2136 return "ice";
2137 else if (((ltyp != POOL) && (ltyp != WATER) &&
2138 !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz) && !Is_juiblex_level(&u.uz)) ||
2139 (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT))
2140 return "moat";
2141 else if ((ltyp != POOL) && (ltyp != WATER) && Is_juiblex_level(&u.uz))
2142 return "swamp";
2143 else if (ltyp == POOL)
2144 return "pool of water";
2145 else if (ltyp == MOORLAND)
2146 return "moorland";
2147 else if (ltyp == URINELAKE)
2148 return "urine lake";
2149 else if (ltyp == STYXRIVER)
2150 return "styx river";
2151 else return "water";
2154 STATIC_OVL void
2155 set_wportal()
2157 /* there better be only one magic portal on water level... */
2158 for (wportal = ftrap; wportal; wportal = wportal->ntrap)
2159 if (wportal->ttyp == MAGIC_PORTAL) return;
2160 impossible("set_wportal(): no portal!");
2163 STATIC_OVL void
2164 setup_waterlevel()
2166 register int x, y;
2167 register int xskip, yskip;
2169 /* ouch, hardcoded... */
2171 #ifdef BIGSLEX
2172 xmin = 26;
2173 ymin = 13;
2174 xmax = 101;
2175 ymax = 32;
2176 #else
2177 xmin = 3;
2178 ymin = 1;
2179 xmax = 78;
2180 ymax = 20;
2181 #endif
2183 /* set hero's memory to water */
2185 for (x = xmin; x <= xmax; x++)
2186 for (y = ymin; y <= ymax; y++)
2187 clear_memory_glyph(x, y, S_water);
2189 /* make bubbles */
2191 xskip = 10 + rn2(10);
2192 yskip = 4 + rn2(4);
2193 for (x = bxmin; x <= bxmax; x += xskip)
2194 for (y = bymin; y <= bymax; y += yskip)
2195 mk_bubble(x,y,rn2(7));
2198 STATIC_OVL void
2199 unsetup_waterlevel()
2201 register struct bubble *b, *bb;
2203 /* free bubbles */
2205 for (b = bbubbles; b; b = bb) {
2206 bb = b->next;
2207 free((void *)b);
2209 bbubbles = ebubbles = (struct bubble *)0;
2212 STATIC_OVL void
2213 mk_bubble(x,y,n)
2214 register int x, y, n;
2217 * These bit masks make visually pleasing bubbles on a normal aspect
2218 * 25x80 terminal, which naturally results in them being mathematically
2219 * anything but symmetric. For this reason they cannot be computed
2220 * in situ, either. The first two elements tell the dimensions of
2221 * the bubble's bounding box.
2223 static uchar
2224 bm2[] = {2,1,0x3},
2225 bm3[] = {3,2,0x7,0x7},
2226 bm4[] = {4,3,0x6,0xf,0x6},
2227 bm5[] = {5,3,0xe,0x1f,0xe},
2228 bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e},
2229 bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e},
2230 bm8[] = {8,4,0x7e,0xff,0xff,0x7e},
2231 *bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8};
2233 register struct bubble *b;
2235 if (x >= bxmax || y >= bymax) return;
2236 if (n >= SIZE(bmask)) {
2237 impossible("n too large (mk_bubble)");
2238 n = SIZE(bmask) - 1;
2240 b = (struct bubble *)alloc(sizeof(struct bubble));
2241 if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1;
2242 if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1;
2243 b->x = x;
2244 b->y = y;
2245 b->dx = 1 - rn2(3);
2246 b->dy = 1 - rn2(3);
2247 b->bm = bmask[n];
2248 b->cons = 0;
2249 if (!bbubbles) bbubbles = b;
2250 if (ebubbles) {
2251 ebubbles->next = b;
2252 b->prev = ebubbles;
2254 else
2255 b->prev = (struct bubble *)0;
2256 b->next = (struct bubble *)0;
2257 ebubbles = b;
2258 mv_bubble(b,0,0,TRUE);
2262 * The player, the portal and all other objects and monsters
2263 * float along with their associated bubbles. Bubbles may overlap
2264 * freely, and the contents may get associated with other bubbles in
2265 * the process. Bubbles are "sticky", meaning that if the player is
2266 * in the immediate neighborhood of one, he/she may get sucked inside.
2267 * This property also makes leaving a bubble slightly difficult.
2269 STATIC_OVL void
2270 mv_bubble(b,dx,dy,ini)
2271 register struct bubble *b;
2272 register int dx, dy;
2273 register boolean ini;
2275 register int x, y, i, j, colli = 0;
2276 struct container *cons, *ctemp;
2278 /* move bubble */
2279 if (dx < -1 || dx > 1 || dy < -1 || dy > 1) {
2280 /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
2281 dx = sgn(dx);
2282 dy = sgn(dy);
2286 * collision with level borders?
2287 * 1 = horizontal border, 2 = vertical, 3 = corner
2289 if (b->x <= bxmin) colli |= 2;
2290 if (b->y <= bymin) colli |= 1;
2291 if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2;
2292 if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1;
2294 if (b->x < bxmin) {
2295 pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin);
2296 b->x = bxmin;
2298 if (b->y < bymin) {
2299 pline("bubble ymin: y = %d, ymin = %d", b->y, bymin);
2300 b->y = bymin;
2302 if ((int) (b->x + b->bm[0] - 1) > bxmax) {
2303 pline("bubble xmax: x = %d, xmax = %d",
2304 b->x + b->bm[0] - 1, bxmax);
2305 b->x = bxmax - b->bm[0] + 1;
2307 if ((int) (b->y + b->bm[1] - 1) > bymax) {
2308 pline("bubble ymax: y = %d, ymax = %d",
2309 b->y + b->bm[1] - 1, bymax);
2310 b->y = bymax - b->bm[1] + 1;
2313 /* bounce if we're trying to move off the border */
2314 if (b->x == bxmin && dx < 0) dx = -dx;
2315 if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx;
2316 if (b->y == bymin && dy < 0) dy = -dy;
2317 if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy;
2319 b->x += dx;
2320 b->y += dy;
2322 /* void positions inside bubble */
2324 for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
2325 for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
2326 if (b->bm[j + 2] & (1 << i)) {
2327 levl[x][y].typ = AIR;
2328 levl[x][y].lit = 1;
2329 unblock_point(x,y);
2332 /* replace contents of bubble */
2333 for (cons = b->cons; cons; cons = ctemp) {
2334 ctemp = cons->next;
2335 cons->x += dx;
2336 cons->y += dy;
2338 switch(cons->what) {
2339 case CONS_OBJ: {
2340 struct obj *olist, *otmp;
2342 for (olist=(struct obj *)cons->list; olist; olist=otmp) {
2343 otmp = olist->nexthere;
2344 place_object(olist, cons->x, cons->y);
2346 break;
2349 case CONS_MON: {
2350 struct monst *mon = (struct monst *) cons->list;
2351 (void) mnearto(mon, cons->x, cons->y, TRUE);
2352 break;
2355 case CONS_HERO: {
2356 int ux0 = u.ux, uy0 = u.uy;
2358 /* change u.ux0 and u.uy0? */
2359 u.ux = cons->x;
2360 u.uy = cons->y;
2361 newsym(ux0, uy0); /* clean up old position */
2363 if (MON_AT(cons->x, cons->y)) {
2364 mnexto(m_at(cons->x,cons->y));
2366 /* WAC removed this. The ball and chain is moved
2367 * as a CONS_OBJECT by the bubble
2369 #if 0
2370 if (Punished) placebc(); /* do this for now */
2371 #endif
2372 break;
2375 case CONS_TRAP: {
2376 struct trap *btrap = (struct trap *) cons->list;
2377 btrap->tx = cons->x;
2378 btrap->ty = cons->y;
2379 break;
2382 default:
2383 impossible("mv_bubble: unknown bubble contents");
2384 break;
2386 free((void *)cons);
2388 b->cons = 0;
2390 /* boing? */
2392 switch (colli) {
2393 case 1: b->dy = -b->dy; break;
2394 case 3: b->dy = -b->dy; /* fall through */
2395 case 2: b->dx = -b->dx; break;
2396 default:
2397 /* sometimes alter direction for fun anyway
2398 (higher probability for stationary bubbles) */
2399 if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) {
2400 b->dx = 1 - rn2(3);
2401 b->dy = 1 - rn2(3);
2406 /*mkmaze.c*/