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