OSDN Git Service

add gitignore
[nethackexpress/trunk.git] / src / dbridge.c
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
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
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
354 STATIC_OVL boolean
355 e_survives_at(etmp, x, y)
356 struct entity *etmp;
357 int 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
377 STATIC_OVL void
378 e_died(etmp, dest, how)
379 struct entity *etmp;
380 int 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
442 STATIC_OVL boolean
443 automiss(etmp)
444 struct 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
454 STATIC_OVL boolean
455 e_missed(etmp, chunks)
456 struct entity *etmp;
457 boolean 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
495 STATIC_OVL boolean
496 e_jumps(etmp)
497 struct 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
521 STATIC_OVL void
522 do_entity(etmp)
523 struct 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
747 void
748 close_drawbridge(x,y)
749 int 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
799 void
800 open_drawbridge(x,y)
801 int 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
837 void
838 destroy_drawbridge(x,y)
839 int 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*/