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