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#ifdef OVLB
16STATIC_DCL void FDECL(get_wall_for_db, (int *, int *));
17STATIC_DCL struct entity *FDECL(e_at, (int, int));
18STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *));
19STATIC_DCL void FDECL(u_to_e, (struct entity *));
20STATIC_DCL void FDECL(set_entity, (int, int, struct entity *));
21STATIC_DCL const char *FDECL(e_nam, (struct entity *));
22#ifdef D_DEBUG
23static const char *FDECL(Enam, (struct entity *)); /* unused */
24#endif
25STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *));
26STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int));
27STATIC_DCL void FDECL(e_died, (struct entity *, int, int));
28STATIC_DCL boolean FDECL(automiss, (struct entity *));
29STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P));
30STATIC_DCL boolean FDECL(e_jumps, (struct entity *));
31STATIC_DCL void FDECL(do_entity, (struct entity *));
32#endif /* OVLB */
33
34#ifdef OVL0
35
36boolean
37is_pool(x,y)
38int 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
50boolean
51is_lava(x,y)
52int 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
64boolean
65is_ice(x,y)
66int 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
89int
90is_drawbridge_wall(x,y)
91int 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 */
120boolean
121is_db_wall(x,y)
122int 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 */
132boolean
133find_drawbridge(x,y)
134int *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 */
159STATIC_OVL void
160get_wall_for_db(x,y)
161int *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
177boolean
178create_drawbridge(x,y,dir,flag)
179int x,y,dir;
180boolean 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
227struct 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
235static NEARDATA struct entity occupants[ENTITIES];
236
237STATIC_OVL
238struct entity *
239e_at(x, y)
240int 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
257STATIC_OVL void
258m_to_e(mtmp, x, y, etmp)
259struct monst *mtmp;
260int x, y;
261struct 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
275STATIC_OVL void
276u_to_e(etmp)
277struct entity *etmp;
278{
279	etmp->emon = &youmonst;
280	etmp->ex = u.ux;
281	etmp->ey = u.uy;
282	etmp->edata = youmonst.data;
283}
284
285STATIC_OVL void
286set_entity(x, y, etmp)
287int x, y;
288struct 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
308STATIC_OVL const char *
309e_nam(etmp)
310struct 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
320static const char *
321Enam(etmp)
322struct 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
333STATIC_OVL const char *
334E_phrase(etmp, verb)
335struct entity *etmp;
336const char *verb;
337{
338	static char wholebuf[80];
339
340	Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon));
341	if (!*verb) return(wholebuf);
342	Strcat(wholebuf, " ");
343	if (is_u(etmp))
344	    Strcat(wholebuf, verb);
345	else
346	    Strcat(wholebuf, vtense((char *)0, verb));
347	return(wholebuf);
348}
349
350/*
351 * Simple-minded "can it be here?" routine
352 */
353
354STATIC_OVL boolean
355e_survives_at(etmp, x, y)
356struct entity *etmp;
357int x, y;
358{
359	if (noncorporeal(etmp->edata))
360		return(TRUE);
361	if (is_pool(x, y))
362		return (boolean)((is_u(etmp) &&
363				(Wwalking || Amphibious || Swimming ||
364				Flying || Levitation)) ||
365			is_swimmer(etmp->edata) || is_flyer(etmp->edata) ||
366			is_floater(etmp->edata));
367	/* must force call to lava_effects in e_died if is_u */
368	if (is_lava(x, y))
369		return (boolean)((is_u(etmp) && (Levitation || Flying)) ||
370			    likes_lava(etmp->edata) || is_flyer(etmp->edata));
371	if (is_db_wall(x, y))
372		return((boolean)(is_u(etmp) ? Passes_walls :
373			passes_walls(etmp->edata)));
374	return(TRUE);
375}
376
377STATIC_OVL void
378e_died(etmp, dest, how)
379struct entity *etmp;
380int dest, how;
381{
382	if (is_u(etmp)) {
383		if (how == DROWNING) {
384			killer = 0;	/* drown() sets its own killer */
385			(void) drown();
386		} else if (how == BURNING) {
387			killer = 0;	/* lava_effects() sets its own killer */
388			(void) lava_effects();
389		} else {
390			coord xy;
391
392			/* use more specific killer if specified */
393			if (!killer) {
394			    killer_format = KILLED_BY_AN;
395			    killer = "falling drawbridge";
396			}
397			done(how);
398			/* So, you didn't die */
399			if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
400			    if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
401				pline("A %s force teleports you away...",
402				      Hallucination ? "normal" : "strange");
403				teleds(xy.x, xy.y, FALSE);
404			    }
405			    /* otherwise on top of the drawbridge is the
406			     * only viable spot in the dungeon, so stay there
407			     */
408			}
409		}
410		/* we might have crawled out of the moat to survive */
411		etmp->ex = u.ux,  etmp->ey = u.uy;
412	} else {
413		int entitycnt;
414
415		killer = 0;
416		/* fake "digested to death" damage-type suppresses corpse */
417#define mk_message(dest) ((dest & 1) ? "" : (char *)0)
418#define mk_corpse(dest)  ((dest & 2) ? AD_DGST : AD_PHYS)
419		/* if monsters are moving, one of them caused the destruction */
420		if (flags.mon_moving)
421		    monkilled(etmp->emon, mk_message(dest), mk_corpse(dest));
422		else		/* you caused it */
423		    xkilled(etmp->emon, dest);
424		etmp->edata = (struct permonst *)0;
425
426		/* dead long worm handling */
427		for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) {
428		    if (etmp != &(occupants[entitycnt]) &&
429			etmp->emon == occupants[entitycnt].emon)
430			occupants[entitycnt].edata = (struct permonst *)0;
431		}
432#undef mk_message
433#undef mk_corpse
434	}
435}
436
437
438/*
439 * These are never directly affected by a bridge or portcullis.
440 */
441
442STATIC_OVL boolean
443automiss(etmp)
444struct entity *etmp;
445{
446	return (boolean)((is_u(etmp) ? Passes_walls :
447			passes_walls(etmp->edata)) || noncorporeal(etmp->edata));
448}
449
450/*
451 * Does falling drawbridge or portcullis miss etmp?
452 */
453
454STATIC_OVL boolean
455e_missed(etmp, chunks)
456struct entity *etmp;
457boolean chunks;
458{
459	int misses;
460
461#ifdef D_DEBUG
462	if (chunks)
463		pline("Do chunks miss?");
464#endif
465	if (automiss(etmp))
466		return(TRUE);
467
468	if (is_flyer(etmp->edata) &&
469	    (is_u(etmp)? !Sleeping :
470	     (etmp->emon->mcanmove && !etmp->emon->msleeping)))
471						 /* flying requires mobility */
472		misses = 5;	/* out of 8 */
473	else if (is_floater(etmp->edata) ||
474		    (is_u(etmp) && Levitation))	 /* doesn't require mobility */
475		misses = 3;
476	else if (chunks && is_pool(etmp->ex, etmp->ey))
477		misses = 2;				    /* sitting ducks */
478	else
479		misses = 0;
480
481	if (is_db_wall(etmp->ex, etmp->ey))
482		misses -= 3;				    /* less airspace */
483
484#ifdef D_DEBUG
485	pline("Miss chance = %d (out of 8)", misses);
486#endif
487
488	return((boolean)((misses >= rnd(8))? TRUE : FALSE));
489}
490
491/*
492 * Can etmp jump from death?
493 */
494
495STATIC_OVL boolean
496e_jumps(etmp)
497struct entity *etmp;
498{
499	int tmp = 4;		/* out of 10 */
500
501	if (is_u(etmp)? (Sleeping || Fumbling) :
502		        (!etmp->emon->mcanmove || etmp->emon->msleeping ||
503			 !etmp->edata->mmove   || etmp->emon->wormno))
504		return(FALSE);
505
506	if (is_u(etmp)? Confusion : etmp->emon->mconf)
507		tmp -= 2;
508
509	if (is_u(etmp)? Stunned : etmp->emon->mstun)
510		tmp -= 3;
511
512	if (is_db_wall(etmp->ex, etmp->ey))
513		tmp -= 2;			    /* less room to maneuver */
514
515#ifdef D_DEBUG
516	pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp);
517#endif
518	return((boolean)((tmp >= rnd(10))? TRUE : FALSE));
519}
520
521STATIC_OVL void
522do_entity(etmp)
523struct entity *etmp;
524{
525	int newx, newy, at_portcullis, oldx, oldy;
526	boolean must_jump = FALSE, relocates = FALSE, e_inview;
527	struct rm *crm;
528
529	if (!etmp->edata)
530		return;
531
532	e_inview = e_canseemon(etmp);
533	oldx = etmp->ex;
534	oldy = etmp->ey;
535	at_portcullis = is_db_wall(oldx, oldy);
536	crm = &levl[oldx][oldy];
537
538	if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
539		if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
540			pline_The("%s passes through %s!",
541			      at_portcullis ? "portcullis" : "drawbridge",
542			      e_nam(etmp));
543		if (is_u(etmp)) spoteffects(FALSE);
544		return;
545	}
546	if (e_missed(etmp, FALSE)) {
547		if (at_portcullis)
548			pline_The("portcullis misses %s!",
549			      e_nam(etmp));
550#ifdef D_DEBUG
551		else
552			pline_The("drawbridge misses %s!",
553			      e_nam(etmp));
554#endif
555		if (e_survives_at(etmp, oldx, oldy))
556			return;
557		else {
558#ifdef D_DEBUG
559			pline("Mon can't survive here");
560#endif
561			if (at_portcullis)
562				must_jump = TRUE;
563			else
564				relocates = TRUE; /* just ride drawbridge in */
565		}
566	} else {
567		if (crm->typ == DRAWBRIDGE_DOWN) {
568			pline("%s crushed underneath the drawbridge.",
569			      E_phrase(etmp, "are"));		  /* no jump */
570			e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */
571			return;   /* Note: Beyond this point, we know we're  */
572		}		  /* not at an opened drawbridge, since all  */
573		must_jump = TRUE; /* *missable* creatures survive on the     */
574	}			  /* square, and all the unmissed ones die.  */
575	if (must_jump) {
576	    if (at_portcullis) {
577		if (e_jumps(etmp)) {
578		    relocates = TRUE;
579#ifdef D_DEBUG
580		    pline("Jump succeeds!");
581#endif
582		} else {
583		    if (e_inview)
584			pline("%s crushed by the falling portcullis!",
585			      E_phrase(etmp, "are"));
586		    else if (flags.soundok)
587			You_hear("a crushing sound.");
588		    e_died(etmp, e_inview? 3 : 2, CRUSHING);
589		    /* no corpse */
590		    return;
591		}
592	    } else { /* tries to jump off bridge to original square */
593		relocates = !e_jumps(etmp);
594#ifdef D_DEBUG
595		pline("Jump %s!", (relocates)? "fails" : "succeeds");
596#endif
597	    }
598	}
599
600/*
601 * Here's where we try to do relocation.  Assumes that etmp is not arriving
602 * at the portcullis square while the drawbridge is falling, since this square
603 * would be inaccessible (i.e. etmp started on drawbridge square) or
604 * unnecessary (i.e. etmp started here) in such a situation.
605 */
606#ifdef D_DEBUG
607	pline("Doing relocation.");
608#endif
609	newx = oldx;
610	newy = oldy;
611	(void)find_drawbridge(&newx, &newy);
612	if ((newx == oldx) && (newy == oldy))
613		get_wall_for_db(&newx, &newy);
614#ifdef D_DEBUG
615	pline("Checking new square for occupancy.");
616#endif
617	if (relocates && (e_at(newx, newy))) {
618
619/*
620 * Standoff problem:  one or both entities must die, and/or both switch
621 * places.  Avoid infinite recursion by checking first whether the other
622 * entity is staying put.  Clean up if we happen to move/die in recursion.
623 */
624		struct entity *other;
625
626		other = e_at(newx, newy);
627#ifdef D_DEBUG
628		pline("New square is occupied by %s", e_nam(other));
629#endif
630		if (e_survives_at(other, newx, newy) && automiss(other)) {
631			relocates = FALSE;	      /* "other" won't budge */
632#ifdef D_DEBUG
633			pline("%s suicide.", E_phrase(etmp, "commit"));
634#endif
635		} else {
636
637#ifdef D_DEBUG
638			pline("Handling %s", e_nam(other));
639#endif
640			while ((e_at(newx, newy) != 0) &&
641			       (e_at(newx, newy) != etmp))
642				do_entity(other);
643#ifdef D_DEBUG
644			pline("Checking existence of %s", e_nam(etmp));
645			wait_synch();
646#endif
647			if (e_at(oldx, oldy) != etmp) {
648#ifdef D_DEBUG
649			    pline("%s moved or died in recursion somewhere",
650				  E_phrase(etmp, "have"));
651			    wait_synch();
652#endif
653			    return;
654			}
655		}
656	}
657	if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */
658#ifdef D_DEBUG
659		pline("Moving %s", e_nam(etmp));
660#endif
661		if (!is_u(etmp)) {
662			remove_monster(etmp->ex, etmp->ey);
663			place_monster(etmp->emon, newx, newy);
664			update_monster_region(etmp->emon);
665		} else {
666			u.ux = newx;
667			u.uy = newy;
668		}
669		etmp->ex = newx;
670		etmp->ey = newy;
671		e_inview = e_canseemon(etmp);
672	}
673#ifdef D_DEBUG
674	pline("Final disposition of %s", e_nam(etmp));
675	wait_synch();
676#endif
677	if (is_db_wall(etmp->ex, etmp->ey)) {
678#ifdef D_DEBUG
679		pline("%s in portcullis chamber", E_phrase(etmp, "are"));
680		wait_synch();
681#endif
682		if (e_inview) {
683			if (is_u(etmp)) {
684				You("tumble towards the closed portcullis!");
685				if (automiss(etmp))
686					You("pass through it!");
687				else
688					pline_The("drawbridge closes in...");
689			} else
690				pline("%s behind the drawbridge.",
691				      E_phrase(etmp, "disappear"));
692		}
693		if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
694			killer_format = KILLED_BY_AN;
695			killer = "closing drawbridge";
696			e_died(etmp, 0, CRUSHING);	       /* no message */
697			return;
698		}
699#ifdef D_DEBUG
700		pline("%s in here", E_phrase(etmp, "survive"));
701#endif
702	} else {
703#ifdef D_DEBUG
704		pline("%s on drawbridge square", E_phrase(etmp, "are"));
705#endif
706		if (is_pool(etmp->ex, etmp->ey) && !e_inview)
707			if (flags.soundok)
708				You_hear("a splash.");
709		if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
710			if (e_inview && !is_flyer(etmp->edata) &&
711			    !is_floater(etmp->edata))
712				pline("%s from the bridge.",
713				      E_phrase(etmp, "fall"));
714			return;
715		}
716#ifdef D_DEBUG
717		pline("%s cannot survive on the drawbridge square",Enam(etmp));
718#endif
719		if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey))
720		    if (e_inview && !is_u(etmp)) {
721			/* drown() will supply msgs if nec. */
722			boolean lava = is_lava(etmp->ex, etmp->ey);
723
724			if (Hallucination)
725			    pline("%s the %s and disappears.",
726				  E_phrase(etmp, "drink"),
727				  lava ? "lava" : "moat");
728			else
729			    pline("%s into the %s.",
730				  E_phrase(etmp, "fall"),
731				  lava ? "lava" : "moat");
732		    }
733		killer_format = NO_KILLER_PREFIX;
734		killer = "fell from a drawbridge";
735		e_died(etmp, e_inview ? 3 : 2,      /* CRUSHING is arbitrary */
736		       (is_pool(etmp->ex, etmp->ey)) ? DROWNING :
737		       (is_lava(etmp->ex, etmp->ey)) ? BURNING :
738						       CRUSHING); /*no corpse*/
739		return;
740	}
741}
742
743/*
744 * Close the drawbridge located at x,y
745 */
746
747void
748close_drawbridge(x,y)
749int x,y;
750{
751	register struct rm *lev1, *lev2;
752	struct trap *t;
753	int x2, y2;
754
755	lev1 = &levl[x][y];
756	if (lev1->typ != DRAWBRIDGE_DOWN) return;
757	x2 = x; y2 = y;
758	get_wall_for_db(&x2,&y2);
759	if (cansee(x,y) || cansee(x2,y2))
760		You("see a drawbridge %s up!",
761		    (((u.ux == x || u.uy == y) && !Underwater) ||
762		     distu(x2,y2) < distu(x,y)) ? "coming" : "going");
763	lev1->typ = DRAWBRIDGE_UP;
764	lev2 = &levl[x2][y2];
765	lev2->typ = DBWALL;
766	switch (lev1->drawbridgemask & DB_DIR) {
767		case DB_NORTH:
768		case DB_SOUTH:
769			lev2->horizontal = TRUE;
770			break;
771		case DB_WEST:
772		case DB_EAST:
773			lev2->horizontal = FALSE;
774			break;
775	}
776	lev2->wall_info = W_NONDIGGABLE;
777	set_entity(x, y, &(occupants[0]));
778	set_entity(x2, y2, &(occupants[1]));
779	do_entity(&(occupants[0]));		/* Do set_entity after first */
780	set_entity(x2, y2, &(occupants[1]));	/* do_entity for worm tail */
781	do_entity(&(occupants[1]));
782	if(OBJ_AT(x,y) && flags.soundok)
783	    You_hear("smashing and crushing.");
784	(void) revive_nasty(x,y,(char *)0);
785	(void) revive_nasty(x2,y2,(char *)0);
786	delallobj(x, y);
787	delallobj(x2, y2);
788	if ((t = t_at(x, y)) != 0) deltrap(t);
789	if ((t = t_at(x2, y2)) != 0) deltrap(t);
790	newsym(x, y);
791	newsym(x2, y2);
792	block_point(x2,y2);	/* vision */
793}
794
795/*
796 * Open the drawbridge located at x,y
797 */
798
799void
800open_drawbridge(x,y)
801int x,y;
802{
803	register struct rm *lev1, *lev2;
804	struct trap *t;
805	int x2, y2;
806
807	lev1 = &levl[x][y];
808	if (lev1->typ != DRAWBRIDGE_UP) return;
809	x2 = x; y2 = y;
810	get_wall_for_db(&x2,&y2);
811	if (cansee(x,y) || cansee(x2,y2))
812		You("see a drawbridge %s down!",
813		    (distu(x2,y2) < distu(x,y)) ? "going" : "coming");
814	lev1->typ = DRAWBRIDGE_DOWN;
815	lev2 = &levl[x2][y2];
816	lev2->typ = DOOR;
817	lev2->doormask = D_NODOOR;
818	set_entity(x, y, &(occupants[0]));
819	set_entity(x2, y2, &(occupants[1]));
820	do_entity(&(occupants[0]));		/* do set_entity after first */
821	set_entity(x2, y2, &(occupants[1]));	/* do_entity for worm tails */
822	do_entity(&(occupants[1]));
823	(void) revive_nasty(x,y,(char *)0);
824	delallobj(x, y);
825	if ((t = t_at(x, y)) != 0) deltrap(t);
826	if ((t = t_at(x2, y2)) != 0) deltrap(t);
827	newsym(x, y);
828	newsym(x2, y2);
829	unblock_point(x2,y2);	/* vision */
830	if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
831}
832
833/*
834 * Let's destroy the drawbridge located at x,y
835 */
836
837void
838destroy_drawbridge(x,y)
839int x,y;
840{
841	register struct rm *lev1, *lev2;
842	struct trap *t;
843	int x2, y2;
844	boolean e_inview;
845	struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]);
846
847	lev1 = &levl[x][y];
848	if (!IS_DRAWBRIDGE(lev1->typ))
849		return;
850	x2 = x; y2 = y;
851	get_wall_for_db(&x2,&y2);
852	lev2 = &levl[x2][y2];
853	if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT ||
854	    (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) {
855		struct obj *otmp;
856		boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA;
857		if (lev1->typ == DRAWBRIDGE_UP) {
858			if (cansee(x2,y2))
859			    pline_The("portcullis of the drawbridge falls into the %s!",
860				  lava ? "lava" : "moat");
861			else if (flags.soundok)
862				You_hear("a loud *SPLASH*!");
863		} else {
864			if (cansee(x,y))
865			    pline_The("drawbridge collapses into the %s!",
866				  lava ? "lava" : "moat");
867			else if (flags.soundok)
868				You_hear("a loud *SPLASH*!");
869		}
870		lev1->typ = lava ? LAVAPOOL : MOAT;
871		lev1->drawbridgemask = 0;
872		if ((otmp = sobj_at(BOULDER,x,y)) != 0) {
873		    obj_extract_self(otmp);
874		    (void) flooreffects(otmp,x,y,"fall");
875		}
876	} else {
877		if (cansee(x,y))
878			pline_The("drawbridge disintegrates!");
879		else
880			You_hear("a loud *CRASH*!");
881		lev1->typ =
882			((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM);
883		lev1->icedpool =
884			((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0);
885	}
886	wake_nearto(x, y, 500);
887	lev2->typ = DOOR;
888	lev2->doormask = D_NODOOR;
889	if ((t = t_at(x, y)) != 0) deltrap(t);
890	if ((t = t_at(x2, y2)) != 0) deltrap(t);
891	newsym(x,y);
892	newsym(x2,y2);
893	if (!does_block(x2,y2,lev2)) unblock_point(x2,y2);	/* vision */
894	if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
895
896	set_entity(x2, y2, etmp2); /* currently only automissers can be here */
897	if (etmp2->edata) {
898		e_inview = e_canseemon(etmp2);
899		if (!automiss(etmp2)) {
900			if (e_inview)
901				pline("%s blown apart by flying debris.",
902				      E_phrase(etmp2, "are"));
903			killer_format = KILLED_BY_AN;
904			killer = "exploding drawbridge";
905			e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/
906		}	     /* nothing which is vulnerable can survive this */
907	}
908	set_entity(x, y, etmp1);
909	if (etmp1->edata) {
910		e_inview = e_canseemon(etmp1);
911		if (e_missed(etmp1, TRUE)) {
912#ifdef D_DEBUG
913			pline("%s spared!", E_phrase(etmp1, "are"));
914#endif
915		} else {
916			if (e_inview) {
917			    if (!is_u(etmp1) && Hallucination)
918				pline("%s into some heavy metal!",
919				      E_phrase(etmp1, "get"));
920			    else
921				pline("%s hit by a huge chunk of metal!",
922				      E_phrase(etmp1, "are"));
923			} else {
924			    if (flags.soundok && !is_u(etmp1) && !is_pool(x,y))
925				You_hear("a crushing sound.");
926#ifdef D_DEBUG
927			    else
928				pline("%s from shrapnel",
929				      E_phrase(etmp1, "die"));
930#endif
931			}
932			killer_format = KILLED_BY_AN;
933			killer = "collapsing drawbridge";
934			e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/
935			if(lev1->typ == MOAT) do_entity(etmp1);
936		}
937	}
938}
939
940#endif /* OVLB */
941
942/*dbridge.c*/
943