1 /*	SCCS Id: @(#)dbridge.c	3.4	2003/02/08	*/
2 /*	Copyright (c) 1989 by Jean-Christophe Collet		  */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /*
6  * This file contains the drawbridge manipulation (create, open, close,
7  * destroy).
8  *
9  * Added comprehensive monster-handling, and the "entity" structure to
10  * deal with players as well. - 11/89
11  */
12 
13 #include "hack.h"
14 
15 STATIC_DCL void FDECL(get_wall_for_db, (int *, int *));
16 STATIC_DCL struct entity *FDECL(e_at, (int, int));
17 STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *));
18 STATIC_DCL void FDECL(u_to_e, (struct entity *));
19 STATIC_DCL void FDECL(set_entity, (int, int, struct entity *));
20 STATIC_DCL const char *FDECL(e_nam, (struct entity *));
21 #ifdef D_DEBUG
22 static const char *FDECL(Enam, (struct entity *)); /* unused */
23 #endif
24 STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *));
25 STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int));
26 STATIC_DCL void FDECL(e_died, (struct entity *, int, int));
27 STATIC_DCL boolean FDECL(automiss, (struct entity *));
28 STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P));
29 STATIC_DCL boolean FDECL(e_jumps, (struct entity *));
30 STATIC_DCL void FDECL(do_entity, (struct entity *));
31 
32 boolean
is_pool(x,y)33 is_pool(x,y)
34 int x,y;
35 {
36     schar ltyp;
37 
38     if (!isok(x,y)) return FALSE;
39     ltyp = levl[x][y].typ;
40     if (ltyp == POOL || ltyp == MOAT || ltyp == WATER) return TRUE;
41     if (ltyp == DRAWBRIDGE_UP &&
42 	(levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT) return TRUE;
43     return FALSE;
44 }
45 
46 boolean
is_lava(x,y)47 is_lava(x,y)
48 int x,y;
49 {
50     schar ltyp;
51 
52     if (!isok(x,y)) return FALSE;
53     ltyp = levl[x][y].typ;
54     if (ltyp == LAVAPOOL
55 	|| (ltyp == DRAWBRIDGE_UP
56 	    && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA)) return TRUE;
57     return FALSE;
58 }
59 
60 boolean
is_any_icewall(x,y)61 is_any_icewall(x, y)
62 int x,y;
63 {
64     if (!isok(x,y)) return FALSE;
65     if (IS_ANY_ICEWALL(levl[x][y].typ))
66 	return TRUE;
67     return FALSE;
68 }
69 
70 boolean
is_ice(x,y)71 is_ice(x,y)
72 int x,y;
73 {
74     schar ltyp;
75 
76     if (!isok(x,y)) return FALSE;
77     ltyp = levl[x][y].typ;
78     if (ltyp == ICE
79 	|| (ltyp == DRAWBRIDGE_UP
80 	    && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) return TRUE;
81     return FALSE;
82 }
83 
84 boolean
is_swamp(x,y)85 is_swamp(x,y)
86 int x,y;
87 {
88     schar ltyp;
89 
90     if (!isok(x,y)) return FALSE;
91     ltyp = levl[x][y].typ;
92     if (ltyp == BOG
93 	|| (ltyp == DRAWBRIDGE_UP
94 	    && (levl[x][y].drawbridgemask & DB_UNDER) == DB_BOG)) return TRUE;
95     return FALSE;
96 }
97 
98 /*
99  * We want to know whether a wall (or a door) is the portcullis (passageway)
100  * of an eventual drawbridge.
101  *
102  * Return value:  the direction of the drawbridge.
103  */
104 
105 int
is_drawbridge_wall(x,y)106 is_drawbridge_wall(x,y)
107 int x,y;
108 {
109 	struct rm *lev;
110 
111 	lev = &levl[x][y];
112 	if (lev->typ != DOOR && lev->typ != DBWALL)
113 		return (-1);
114 
115 	if (IS_DRAWBRIDGE(levl[x+1][y].typ) &&
116 	    (levl[x+1][y].drawbridgemask & DB_DIR) == DB_WEST)
117 		return (DB_WEST);
118 	if (IS_DRAWBRIDGE(levl[x-1][y].typ) &&
119 	    (levl[x-1][y].drawbridgemask & DB_DIR) == DB_EAST)
120 		return (DB_EAST);
121 	if (IS_DRAWBRIDGE(levl[x][y-1].typ) &&
122 	    (levl[x][y-1].drawbridgemask & DB_DIR) == DB_SOUTH)
123 		return (DB_SOUTH);
124 	if (IS_DRAWBRIDGE(levl[x][y+1].typ) &&
125 	    (levl[x][y+1].drawbridgemask & DB_DIR) == DB_NORTH)
126 		return (DB_NORTH);
127 
128 	return (-1);
129 }
130 
131 /*
132  * Use is_db_wall where you want to verify that a
133  * drawbridge "wall" is UP in the location x, y
134  * (instead of UP or DOWN, as with is_drawbridge_wall).
135  */
136 boolean
is_db_wall(x,y)137 is_db_wall(x,y)
138 int x,y;
139 {
140 	return((boolean)( levl[x][y].typ == DBWALL ));
141 }
142 
143 
144 /*
145  * Return true with x,y pointing to the drawbridge if x,y initially indicate
146  * a drawbridge or drawbridge wall.
147  */
148 boolean
find_drawbridge(x,y)149 find_drawbridge(x,y)
150 int *x,*y;
151 {
152 	int dir;
153 
154 	if (IS_DRAWBRIDGE(levl[*x][*y].typ))
155 		return TRUE;
156 	dir = is_drawbridge_wall(*x,*y);
157 	if (dir >= 0) {
158 		switch(dir) {
159 			case DB_NORTH: (*y)++; break;
160 			case DB_SOUTH: (*y)--; break;
161 			case DB_EAST:  (*x)--; break;
162 			case DB_WEST:  (*x)++; break;
163 		}
164 		return TRUE;
165 	}
166 	return FALSE;
167 }
168 
169 /*
170  * Find the drawbridge wall associated with a drawbridge.
171  */
172 STATIC_OVL void
get_wall_for_db(x,y)173 get_wall_for_db(x,y)
174 int *x,*y;
175 {
176 	switch (levl[*x][*y].drawbridgemask & DB_DIR) {
177 		case DB_NORTH: (*y)--; break;
178 		case DB_SOUTH: (*y)++; break;
179 		case DB_EAST:  (*x)++; break;
180 		case DB_WEST:  (*x)--; break;
181 	}
182 }
183 
184 /*
185  * Creation of a drawbridge at pos x,y.
186  *     dir is the direction.
187  *     flag must be put to TRUE if we want the drawbridge to be opened.
188  */
189 
190 boolean
create_drawbridge(x,y,dir,flag)191 create_drawbridge(x,y,dir,flag)
192 int x,y,dir;
193 int flag;
194 {
195 	int x2,y2;
196 	boolean horiz;
197 	boolean lava = levl[x][y].typ == LAVAPOOL; /* assume initialized map */
198 
199 	if (flag < 0 || flag > 1) flag = rn2(2);
200 	x2 = x; y2 = y;
201 	switch(dir) {
202 		case DB_NORTH:
203 			horiz = TRUE;
204 			y2--;
205 			break;
206 		case DB_SOUTH:
207 			horiz = TRUE;
208 			y2++;
209 			break;
210 		case DB_EAST:
211 			horiz = FALSE;
212 			x2++;
213 			break;
214 		default:
215 			impossible("bad direction in create_drawbridge");
216 			/* fall through */
217 		case DB_WEST:
218 			horiz = FALSE;
219 			x2--;
220 			break;
221 	}
222 	if (!IS_WALL(levl[x2][y2].typ))
223 		return(FALSE);
224 	if (flag) {             /* We want the bridge open */
225 		levl[x][y].typ = DRAWBRIDGE_DOWN;
226 		levl[x2][y2].typ = DOOR;
227 		levl[x2][y2].doormask = D_NODOOR;
228 	} else {
229 		levl[x][y].typ = DRAWBRIDGE_UP;
230 		levl[x2][y2].typ = DBWALL;
231 		/* Drawbridges are non-diggable. */
232 		levl[x2][y2].wall_info = W_NONDIGGABLE;
233 	}
234 	levl[x][y].horizontal = !horiz;
235 	levl[x2][y2].horizontal = horiz;
236 	levl[x][y].drawbridgemask = dir;
237 	if(lava) levl[x][y].drawbridgemask |= DB_LAVA;
238 	return(TRUE);
239 }
240 
241 struct entity {
242 	struct monst *emon;	  /* youmonst for the player */
243 	struct permonst *edata;   /* must be non-zero for record to be valid */
244 	int ex, ey;
245 };
246 
247 #define ENTITIES 2
248 
249 static NEARDATA struct entity occupants[ENTITIES];
250 
251 STATIC_OVL
252 struct entity *
e_at(x,y)253 e_at(x, y)
254 int x, y;
255 {
256 	int entitycnt;
257 
258 	for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++)
259 		if ((occupants[entitycnt].edata) &&
260 		    (occupants[entitycnt].ex == x) &&
261 		    (occupants[entitycnt].ey == y))
262 			break;
263 #ifdef D_DEBUG
264 	pline("entitycnt = %d", entitycnt);
265 	wait_synch();
266 #endif
267 	return((entitycnt == ENTITIES)?
268 	       (struct entity *)0 : &(occupants[entitycnt]));
269 }
270 
271 STATIC_OVL void
m_to_e(mtmp,x,y,etmp)272 m_to_e(mtmp, x, y, etmp)
273 struct monst *mtmp;
274 int x, y;
275 struct entity *etmp;
276 {
277 	etmp->emon = mtmp;
278 	if (mtmp) {
279 		etmp->ex = x;
280 		etmp->ey = y;
281 		if (mtmp->wormno && (x != mtmp->mx || y != mtmp->my))
282 			etmp->edata = &mons[PM_LONG_WORM_TAIL];
283 		else
284 			etmp->edata = mtmp->data;
285 	} else
286 		etmp->edata = (struct permonst *)0;
287 }
288 
289 STATIC_OVL void
u_to_e(etmp)290 u_to_e(etmp)
291 struct entity *etmp;
292 {
293 	etmp->emon = &youmonst;
294 	etmp->ex = u.ux;
295 	etmp->ey = u.uy;
296 	etmp->edata = youmonst.data;
297 }
298 
299 STATIC_OVL void
set_entity(x,y,etmp)300 set_entity(x, y, etmp)
301 int x, y;
302 struct entity *etmp;
303 {
304 	if ((x == u.ux) && (y == u.uy))
305 		u_to_e(etmp);
306 	else if (MON_AT(x, y))
307 		m_to_e(m_at(x, y), x, y, etmp);
308 	else
309 		etmp->edata = (struct permonst *)0;
310 }
311 
312 #define is_u(etmp) (etmp->emon == &youmonst)
313 #define e_canseemon(etmp) (is_u(etmp) ? (boolean)TRUE : canseemon(etmp->emon))
314 
315 /*
316  * e_strg is a utility routine which is not actually in use anywhere, since
317  * the specialized routines below suffice for all current purposes.
318  */
319 
320 /* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */
321 
322 STATIC_OVL const char *
e_nam(etmp)323 e_nam(etmp)
324 struct entity *etmp;
325 {
326 	return(is_u(etmp)? "you" : mon_nam(etmp->emon));
327 }
328 
329 #ifdef D_DEBUG
330 /*
331  * Enam is another unused utility routine:  E_phrase is preferable.
332  */
333 
334 static const char *
Enam(etmp)335 Enam(etmp)
336 struct entity *etmp;
337 {
338 	return(is_u(etmp)? "You" : Monnam(etmp->emon));
339 }
340 #endif /* D_DEBUG */
341 
342 /*
343  * Generates capitalized entity name, makes 2nd -> 3rd person conversion on
344  * verb, where necessary.
345  */
346 
347 STATIC_OVL const char *
E_phrase(etmp,verb)348 E_phrase(etmp, verb)
349 struct entity *etmp;
350 const char *verb;
351 {
352 	static char wholebuf[80];
353 
354 	Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon));
355 	if (!*verb) return(wholebuf);
356 	Strcat(wholebuf, " ");
357 	if (is_u(etmp))
358 	    Strcat(wholebuf, verb);
359 	else
360 	    Strcat(wholebuf, vtense((char *)0, verb));
361 	return(wholebuf);
362 }
363 
364 /*
365  * Simple-minded "can it be here?" routine
366  */
367 
368 STATIC_OVL boolean
e_survives_at(etmp,x,y)369 e_survives_at(etmp, x, y)
370 struct entity *etmp;
371 int x, y;
372 {
373 	if (noncorporeal(etmp->edata))
374 		return(TRUE);
375 	if (is_pool(x, y))
376 		return (boolean)((is_u(etmp) &&
377 				(Wwalking || Amphibious || Swimming ||
378 				Flying || Levitation)) ||
379 			is_swimmer(etmp->edata) || is_flyer(etmp->edata) ||
380 			is_floater(etmp->edata));
381 	/* must force call to lava_effects in e_died if is_u */
382 	if (is_lava(x, y))
383 		return (boolean)((is_u(etmp) && (Levitation || Flying)) ||
384 			    likes_lava(etmp->edata) || is_flyer(etmp->edata));
385 	if (is_db_wall(x, y))
386 		return((boolean)(is_u(etmp) ? Passes_walls :
387 			passes_walls(etmp->edata)));
388 	return(TRUE);
389 }
390 
391 STATIC_OVL void
e_died(etmp,dest,how)392 e_died(etmp, dest, how)
393 struct entity *etmp;
394 int dest, how;
395 {
396 	if (is_u(etmp)) {
397 		if (how == DROWNING) {
398 			killer = 0;	/* drown() sets its own killer */
399 			(void) drown();
400 		} else if (how == BURNING) {
401 			killer = 0;	/* lava_effects() sets its own killer */
402 			(void) lava_effects();
403 		} else {
404 			coord xy;
405 
406 			/* use more specific killer if specified */
407 			if (!killer) {
408 			    killer_format = KILLED_BY_AN;
409 			    killer = "falling drawbridge";
410 			}
411 			done(how);
412 			/* So, you didn't die */
413 			if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
414 			    if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
415 				pline("A %s force teleports you away...",
416 				      Hallucination ? "normal" : "strange");
417 				teleds(xy.x, xy.y, FALSE);
418 			    }
419 			    /* otherwise on top of the drawbridge is the
420 			     * only viable spot in the dungeon, so stay there
421 			     */
422 			}
423 		}
424 		/* we might have crawled out of the moat to survive */
425 		etmp->ex = u.ux,  etmp->ey = u.uy;
426 	} else {
427 		int entitycnt;
428 
429 		killer = 0;
430 		/* fake "digested to death" damage-type suppresses corpse */
431 #define mk_message(dest) ((dest & 1) ? "" : (char *)0)
432 #define mk_corpse(dest)  ((dest & 2) ? AD_DGST : AD_PHYS)
433 		/* if monsters are moving, one of them caused the destruction */
434 		if (flags.mon_moving)
435 		    monkilled(etmp->emon, mk_message(dest), mk_corpse(dest));
436 		else		/* you caused it */
437 		    xkilled(etmp->emon, dest);
438 		etmp->edata = (struct permonst *)0;
439 
440 		/* dead long worm handling */
441 		for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) {
442 		    if (etmp != &(occupants[entitycnt]) &&
443 			etmp->emon == occupants[entitycnt].emon)
444 			occupants[entitycnt].edata = (struct permonst *)0;
445 		}
446 #undef mk_message
447 #undef mk_corpse
448 	}
449 }
450 
451 
452 /*
453  * These are never directly affected by a bridge or portcullis.
454  */
455 
456 STATIC_OVL boolean
automiss(etmp)457 automiss(etmp)
458 struct entity *etmp;
459 {
460 	return (boolean)((is_u(etmp) ? Passes_walls :
461 			passes_walls(etmp->edata)) || noncorporeal(etmp->edata));
462 }
463 
464 /*
465  * Does falling drawbridge or portcullis miss etmp?
466  */
467 
468 STATIC_OVL boolean
e_missed(etmp,chunks)469 e_missed(etmp, chunks)
470 struct entity *etmp;
471 boolean chunks;
472 {
473 	int misses;
474 
475 #ifdef D_DEBUG
476 	if (chunks)
477 		pline("Do chunks miss?");
478 #endif
479 	if (automiss(etmp))
480 		return(TRUE);
481 
482 	if (is_flyer(etmp->edata) &&
483 	    (is_u(etmp)? !Sleeping :
484 	     (etmp->emon->mcanmove && !etmp->emon->msleeping)))
485 						 /* flying requires mobility */
486 		misses = 5;	/* out of 8 */
487 	else if (is_floater(etmp->edata) ||
488 		    (is_u(etmp) && Levitation))	 /* doesn't require mobility */
489 		misses = 3;
490 	else if (chunks && is_pool(etmp->ex, etmp->ey))
491 		misses = 2;				    /* sitting ducks */
492 	else
493 		misses = 0;
494 
495 	if (is_db_wall(etmp->ex, etmp->ey))
496 		misses -= 3;				    /* less airspace */
497 
498 #ifdef D_DEBUG
499 	pline("Miss chance = %d (out of 8)", misses);
500 #endif
501 
502 	return((boolean)((misses >= rnd(8))? TRUE : FALSE));
503 }
504 
505 /*
506  * Can etmp jump from death?
507  */
508 
509 STATIC_OVL boolean
e_jumps(etmp)510 e_jumps(etmp)
511 struct entity *etmp;
512 {
513 	int tmp = 4;		/* out of 10 */
514 
515 	if (is_u(etmp)? (Sleeping || Fumbling) :
516 		        (!etmp->emon->mcanmove || etmp->emon->msleeping ||
517 			 !etmp->edata->mmove   || etmp->emon->wormno))
518 		return(FALSE);
519 
520 	if (is_u(etmp)? Confusion : etmp->emon->mconf)
521 		tmp -= 2;
522 
523 	if (is_u(etmp)? Stunned : etmp->emon->mstun)
524 		tmp -= 3;
525 
526 	if (is_db_wall(etmp->ex, etmp->ey))
527 		tmp -= 2;			    /* less room to maneuver */
528 
529 #ifdef D_DEBUG
530 	pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp);
531 #endif
532 	return((boolean)((tmp >= rnd(10))? TRUE : FALSE));
533 }
534 
535 STATIC_OVL void
do_entity(etmp)536 do_entity(etmp)
537 struct entity *etmp;
538 {
539 	int newx, newy, at_portcullis, oldx, oldy;
540 	boolean must_jump = FALSE, relocates = FALSE, e_inview;
541 	struct rm *crm;
542 
543 	if (!etmp->edata)
544 		return;
545 
546 	e_inview = e_canseemon(etmp);
547 	oldx = etmp->ex;
548 	oldy = etmp->ey;
549 	at_portcullis = is_db_wall(oldx, oldy);
550 	crm = &levl[oldx][oldy];
551 
552 	if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
553 		if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
554 			pline_The("%s passes through %s!",
555 			      at_portcullis ? "portcullis" : "drawbridge",
556 			      e_nam(etmp));
557 		if (is_u(etmp)) spoteffects(FALSE);
558 		return;
559 	}
560 	if (e_missed(etmp, FALSE)) {
561 		if (at_portcullis)
562 			pline_The("portcullis misses %s!",
563 			      e_nam(etmp));
564 #ifdef D_DEBUG
565 		else
566 			pline_The("drawbridge misses %s!",
567 			      e_nam(etmp));
568 #endif
569 		if (e_survives_at(etmp, oldx, oldy))
570 			return;
571 		else {
572 #ifdef D_DEBUG
573 			pline("Mon can't survive here");
574 #endif
575 			if (at_portcullis)
576 				must_jump = TRUE;
577 			else
578 				relocates = TRUE; /* just ride drawbridge in */
579 		}
580 	} else {
581 		if (crm->typ == DRAWBRIDGE_DOWN) {
582 			pline("%s crushed underneath the drawbridge.",
583 			      E_phrase(etmp, "are"));		  /* no jump */
584 			e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */
585 			return;   /* Note: Beyond this point, we know we're  */
586 		}		  /* not at an opened drawbridge, since all  */
587 		must_jump = TRUE; /* *missable* creatures survive on the     */
588 	}			  /* square, and all the unmissed ones die.  */
589 	if (must_jump) {
590 	    if (at_portcullis) {
591 		if (e_jumps(etmp)) {
592 		    relocates = TRUE;
593 #ifdef D_DEBUG
594 		    pline("Jump succeeds!");
595 #endif
596 		} else {
597 		    if (e_inview)
598 			pline("%s crushed by the falling portcullis!",
599 			      E_phrase(etmp, "are"));
600 		    else if (flags.soundok)
601 			You_hear("a crushing sound.");
602 		    e_died(etmp, e_inview? 3 : 2, CRUSHING);
603 		    /* no corpse */
604 		    return;
605 		}
606 	    } else { /* tries to jump off bridge to original square */
607 		relocates = !e_jumps(etmp);
608 #ifdef D_DEBUG
609 		pline("Jump %s!", (relocates)? "fails" : "succeeds");
610 #endif
611 	    }
612 	}
613 
614 /*
615  * Here's where we try to do relocation.  Assumes that etmp is not arriving
616  * at the portcullis square while the drawbridge is falling, since this square
617  * would be inaccessible (i.e. etmp started on drawbridge square) or
618  * unnecessary (i.e. etmp started here) in such a situation.
619  */
620 #ifdef D_DEBUG
621 	pline("Doing relocation.");
622 #endif
623 	newx = oldx;
624 	newy = oldy;
625 	(void)find_drawbridge(&newx, &newy);
626 	if ((newx == oldx) && (newy == oldy))
627 		get_wall_for_db(&newx, &newy);
628 #ifdef D_DEBUG
629 	pline("Checking new square for occupancy.");
630 #endif
631 	if (relocates && (e_at(newx, newy))) {
632 
633 /*
634  * Standoff problem:  one or both entities must die, and/or both switch
635  * places.  Avoid infinite recursion by checking first whether the other
636  * entity is staying put.  Clean up if we happen to move/die in recursion.
637  */
638 		struct entity *other;
639 
640 		other = e_at(newx, newy);
641 #ifdef D_DEBUG
642 		pline("New square is occupied by %s", e_nam(other));
643 #endif
644 		if (e_survives_at(other, newx, newy) && automiss(other)) {
645 			relocates = FALSE;	      /* "other" won't budge */
646 #ifdef D_DEBUG
647 			pline("%s suicide.", E_phrase(etmp, "commit"));
648 #endif
649 		} else {
650 
651 #ifdef D_DEBUG
652 			pline("Handling %s", e_nam(other));
653 #endif
654 			while ((e_at(newx, newy) != 0) &&
655 			       (e_at(newx, newy) != etmp))
656 				do_entity(other);
657 #ifdef D_DEBUG
658 			pline("Checking existence of %s", e_nam(etmp));
659 			wait_synch();
660 #endif
661 			if (e_at(oldx, oldy) != etmp) {
662 #ifdef D_DEBUG
663 			    pline("%s moved or died in recursion somewhere",
664 				  E_phrase(etmp, "have"));
665 			    wait_synch();
666 #endif
667 			    return;
668 			}
669 		}
670 	}
671 	if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */
672 #ifdef D_DEBUG
673 		pline("Moving %s", e_nam(etmp));
674 #endif
675 		if (!is_u(etmp)) {
676 			remove_monster(etmp->ex, etmp->ey);
677 			place_monster(etmp->emon, newx, newy);
678 			update_monster_region(etmp->emon);
679 		} else {
680 			u.ux = newx;
681 			u.uy = newy;
682 		}
683 		etmp->ex = newx;
684 		etmp->ey = newy;
685 		e_inview = e_canseemon(etmp);
686 	}
687 #ifdef D_DEBUG
688 	pline("Final disposition of %s", e_nam(etmp));
689 	wait_synch();
690 #endif
691 	if (is_db_wall(etmp->ex, etmp->ey)) {
692 #ifdef D_DEBUG
693 		pline("%s in portcullis chamber", E_phrase(etmp, "are"));
694 		wait_synch();
695 #endif
696 		if (e_inview) {
697 			if (is_u(etmp)) {
698 				You("tumble towards the closed portcullis!");
699 				if (automiss(etmp))
700 					You("pass through it!");
701 				else
702 					pline_The("drawbridge closes in...");
703 			} else
704 				pline("%s behind the drawbridge.",
705 				      E_phrase(etmp, "disappear"));
706 		}
707 		if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
708 			killer_format = KILLED_BY_AN;
709 			killer = "closing drawbridge";
710 			e_died(etmp, 0, CRUSHING);	       /* no message */
711 			return;
712 		}
713 #ifdef D_DEBUG
714 		pline("%s in here", E_phrase(etmp, "survive"));
715 #endif
716 	} else {
717 #ifdef D_DEBUG
718 		pline("%s on drawbridge square", E_phrase(etmp, "are"));
719 #endif
720 		if (is_pool(etmp->ex, etmp->ey) && !e_inview)
721 			if (flags.soundok)
722 				You_hear("a splash.");
723 		if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
724 			if (e_inview && !is_flyer(etmp->edata) &&
725 			    !is_floater(etmp->edata))
726 				pline("%s from the bridge.",
727 				      E_phrase(etmp, "fall"));
728 			return;
729 		}
730 #ifdef D_DEBUG
731 		pline("%s cannot survive on the drawbridge square",Enam(etmp));
732 #endif
733 		if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey))
734 		    if (e_inview && !is_u(etmp)) {
735 			/* drown() will supply msgs if nec. */
736 			boolean lava = is_lava(etmp->ex, etmp->ey);
737 
738 			if (Hallucination)
739 			    pline("%s the %s and disappears.",
740 				  E_phrase(etmp, "drink"),
741 				  lava ? "lava" : "moat");
742 			else
743 			    pline("%s into the %s.",
744 				  E_phrase(etmp, "fall"),
745 				  lava ? "lava" : "moat");
746 		    }
747 		killer_format = NO_KILLER_PREFIX;
748 		killer = "fell from a drawbridge";
749 		e_died(etmp, e_inview ? 3 : 2,      /* CRUSHING is arbitrary */
750 		       (is_pool(etmp->ex, etmp->ey)) ? DROWNING :
751 		       (is_lava(etmp->ex, etmp->ey)) ? BURNING :
752 						       CRUSHING); /*no corpse*/
753 		return;
754 	}
755 }
756 
757 /**
758  * Close the drawbridge located at x,y
759  * @return TRUE when drawbridge got closed, FALSE otherwise
760  */
761 boolean
close_drawbridge(x,y)762 close_drawbridge(x,y)
763 int x,y;
764 {
765 	register struct rm *lev1, *lev2;
766 	struct trap *t;
767 	int x2, y2;
768 
769 	lev1 = &levl[x][y];
770 	if (lev1->typ != DRAWBRIDGE_DOWN) return FALSE;
771 	/* Huge monster block the drawbridge */
772 	if (m_at(x,y) && hugemonst(m_at(x,y)->data)) {
773 		pline("A monster blocks the drawbridge with its weight.");
774 		return FALSE;
775 	}
776 	if (rn2(5)==0) {
777 		pline("The mechanism seems to have something stuck in it and won't close.");
778 		return FALSE;
779 	}
780 	x2 = x; y2 = y;
781 	get_wall_for_db(&x2,&y2);
782 	if (cansee(x,y) || cansee(x2,y2))
783 		You("see a drawbridge %s up!",
784 		    (((u.ux == x || u.uy == y) && !Underwater) ||
785 		     distu(x2,y2) < distu(x,y)) ? "coming" : "going");
786 	lev1->typ = DRAWBRIDGE_UP;
787 	lev2 = &levl[x2][y2];
788 	lev2->typ = DBWALL;
789 	switch (lev1->drawbridgemask & DB_DIR) {
790 		case DB_NORTH:
791 		case DB_SOUTH:
792 			lev2->horizontal = TRUE;
793 			break;
794 		case DB_WEST:
795 		case DB_EAST:
796 			lev2->horizontal = FALSE;
797 			break;
798 	}
799 	lev2->wall_info = W_NONDIGGABLE;
800 	set_entity(x, y, &(occupants[0]));
801 	set_entity(x2, y2, &(occupants[1]));
802 	do_entity(&(occupants[0]));		/* Do set_entity after first */
803 	set_entity(x2, y2, &(occupants[1]));	/* do_entity for worm tail */
804 	do_entity(&(occupants[1]));
805 	if(OBJ_AT(x,y) && flags.soundok)
806 	    You_hear("smashing and crushing.");
807 	(void) revive_nasty(x,y,(char *)0);
808 	(void) revive_nasty(x2,y2,(char *)0);
809 	delallobj(x, y);
810 	delallobj(x2, y2);
811 	if ((t = t_at(x, y)) != 0) deltrap(t);
812 	if ((t = t_at(x2, y2)) != 0) deltrap(t);
813 	newsym(x, y);
814 	newsym(x2, y2);
815 	block_point(x2,y2);	/* vision */
816 	return TRUE;
817 }
818 
819 /*
820  * Open the drawbridge located at x,y
821  */
822 
823 void
open_drawbridge(x,y)824 open_drawbridge(x,y)
825 int x,y;
826 {
827 	register struct rm *lev1, *lev2;
828 	struct trap *t;
829 	int x2, y2;
830 
831 	lev1 = &levl[x][y];
832 	if (lev1->typ != DRAWBRIDGE_UP) return;
833 	x2 = x; y2 = y;
834 	get_wall_for_db(&x2,&y2);
835 	if (cansee(x,y) || cansee(x2,y2))
836 		You("see a drawbridge %s down!",
837 		    (distu(x2,y2) < distu(x,y)) ? "going" : "coming");
838 	lev1->typ = DRAWBRIDGE_DOWN;
839 	lev2 = &levl[x2][y2];
840 	lev2->typ = DOOR;
841 	lev2->doormask = D_NODOOR;
842 	set_entity(x, y, &(occupants[0]));
843 	set_entity(x2, y2, &(occupants[1]));
844 	do_entity(&(occupants[0]));		/* do set_entity after first */
845 	set_entity(x2, y2, &(occupants[1]));	/* do_entity for worm tails */
846 	do_entity(&(occupants[1]));
847 	(void) revive_nasty(x,y,(char *)0);
848 	delallobj(x, y);
849 	if ((t = t_at(x, y)) != 0) deltrap(t);
850 	if ((t = t_at(x2, y2)) != 0) deltrap(t);
851 	newsym(x, y);
852 	newsym(x2, y2);
853 	unblock_point(x2,y2);	/* vision */
854 	if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
855 }
856 
857 /*
858  * Let's destroy the drawbridge located at x,y
859  */
860 
861 void
destroy_drawbridge(x,y)862 destroy_drawbridge(x,y)
863 int x,y;
864 {
865 	register struct rm *lev1, *lev2;
866 	struct trap *t;
867 	int x2, y2;
868 	int db_u;
869 	boolean e_inview;
870 	struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]);
871 
872 	lev1 = &levl[x][y];
873 	if (!IS_DRAWBRIDGE(lev1->typ))
874 		return;
875 	x2 = x; y2 = y;
876 	get_wall_for_db(&x2,&y2);
877 	lev2 = &levl[x2][y2];
878 	db_u = (lev1->drawbridgemask & DB_UNDER);
879 	if (db_u == DB_MOAT || db_u == DB_LAVA || db_u == DB_BOG) {
880 		struct obj *otmp;
881 		int where = (db_u == DB_LAVA) ? 0 :
882 			    (db_u == DB_MOAT) ? 1 : 2;
883 		static char *wstr[3] = { "lava", "moat", "swamp" };
884 		if (lev1->typ == DRAWBRIDGE_UP) {
885 			if (cansee(x2,y2))
886 			    pline_The("portcullis of the drawbridge falls into the %s!", wstr[where]);
887 			else if (flags.soundok)
888 				You_hear("a loud *SPLASH*!");
889 		} else {
890 			if (cansee(x,y))
891 			    pline_The("drawbridge collapses into the %s!", wstr[where]);
892 			else if (flags.soundok)
893 				You_hear("a loud *SPLASH*!");
894 		}
895 		lev1->typ = (where == 0) ? LAVAPOOL : (where == 1) ? MOAT : BOG;
896 		lev1->drawbridgemask = 0;
897 		if ((otmp = sobj_at(BOULDER,x,y)) != 0) {
898 		    obj_extract_self(otmp);
899 		    (void) flooreffects(otmp,x,y,"fall");
900 		}
901 	} else {
902 		if (cansee(x,y))
903 			pline_The("drawbridge disintegrates!");
904 		else
905 			You_hear("a loud *CRASH*!");
906 		lev1->typ =
907 			((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM);
908 		lev1->icedpool =
909 			((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0);
910 	}
911 	wake_nearto(x, y, 500);
912 	lev2->typ = DOOR;
913 	lev2->doormask = D_NODOOR;
914 	if ((t = t_at(x, y)) != 0) deltrap(t);
915 	if ((t = t_at(x2, y2)) != 0) deltrap(t);
916 	newsym(x,y);
917 	newsym(x2,y2);
918 	if (!does_block(x2,y2,lev2)) unblock_point(x2,y2);	/* vision */
919 	if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
920 
921 	set_entity(x2, y2, etmp2); /* currently only automissers can be here */
922 	if (etmp2->edata) {
923 		e_inview = e_canseemon(etmp2);
924 		if (!automiss(etmp2)) {
925 			if (e_inview)
926 				pline("%s blown apart by flying debris.",
927 				      E_phrase(etmp2, "are"));
928 			killer_format = KILLED_BY_AN;
929 			killer = "exploding drawbridge";
930 			e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/
931 		}	     /* nothing which is vulnerable can survive this */
932 	}
933 	set_entity(x, y, etmp1);
934 	if (etmp1->edata) {
935 		e_inview = e_canseemon(etmp1);
936 		if (e_missed(etmp1, TRUE)) {
937 #ifdef D_DEBUG
938 			pline("%s spared!", E_phrase(etmp1, "are"));
939 #endif
940 		} else {
941 			if (e_inview) {
942 			    if (!is_u(etmp1) && Hallucination)
943 				pline("%s into some heavy metal!",
944 				      E_phrase(etmp1, "get"));
945 			    else
946 				pline("%s hit by a huge chunk of metal!",
947 				      E_phrase(etmp1, "are"));
948 			} else {
949 			    if (flags.soundok && !is_u(etmp1) && !is_pool(x,y))
950 				You_hear("a crushing sound.");
951 #ifdef D_DEBUG
952 			    else
953 				pline("%s from shrapnel",
954 				      E_phrase(etmp1, "die"));
955 #endif
956 			}
957 			killer_format = KILLED_BY_AN;
958 			killer = "collapsing drawbridge";
959 			e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/
960 			if(lev1->typ == MOAT) do_entity(etmp1);
961 		}
962 	}
963 }
964 
965 /*dbridge.c*/
966