option parsing buffer overflow vulnerability
[aNetHack.git] / src / dbridge.c
blob428161de59697ccad567bb46462f2c1d1e7b095b
1 /* NetHack 3.6 dbridge.c $NHDT-Date: 1449269914 2015/12/04 22:58:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.35 $ */
2 /* Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed. See license for details. */
5 /*
6 * This file contains the drawbridge manipulation (create, open, close,
7 * destroy).
9 * Added comprehensive monster-handling, and the "entity" structure to
10 * deal with players as well. - 11/89
12 * Any traps and/or engravings at either the portcullis or span location
13 * are destroyed whenever the bridge is lowered, raised, or destroyed.
14 * (Engraving handling could be extended to flag whether an engraving on
15 * the DB_UNDER surface is hidden by the lowered bridge, or one on the
16 * bridge itself is hidden because the bridge has been raised, but that
17 * seems like an awful lot of effort for very little gain.)
20 #include "hack.h"
22 STATIC_DCL void FDECL(get_wall_for_db, (int *, int *));
23 STATIC_DCL struct entity *FDECL(e_at, (int, int));
24 STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *));
25 STATIC_DCL void FDECL(u_to_e, (struct entity *));
26 STATIC_DCL void FDECL(set_entity, (int, int, struct entity *));
27 STATIC_DCL const char *FDECL(e_nam, (struct entity *));
28 STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *));
29 STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int));
30 STATIC_DCL void FDECL(e_died, (struct entity *, int, int));
31 STATIC_DCL boolean FDECL(automiss, (struct entity *));
32 STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P));
33 STATIC_DCL boolean FDECL(e_jumps, (struct entity *));
34 STATIC_DCL void FDECL(do_entity, (struct entity *));
36 boolean
37 is_pool(x, y)
38 int x, y;
40 schar ltyp;
42 if (!isok(x, y))
43 return FALSE;
44 ltyp = levl[x][y].typ;
45 /* The ltyp == MOAT is not redundant with is_moat, because the
46 * Juiblex level does not have moats, although it has MOATs. There
47 * is probably a better way to express this. */
48 if (ltyp == POOL || ltyp == MOAT || ltyp == WATER || is_moat(x, y))
49 return TRUE;
50 return FALSE;
53 boolean
54 is_lava(x, y)
55 int x, y;
57 schar ltyp;
59 if (!isok(x, y))
60 return FALSE;
61 ltyp = levl[x][y].typ;
62 if (ltyp == LAVAPOOL
63 || (ltyp == DRAWBRIDGE_UP
64 && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA))
65 return TRUE;
66 return FALSE;
69 boolean
70 is_pool_or_lava(x, y)
71 int x, y;
73 if (is_pool(x, y) || is_lava(x, y))
74 return TRUE;
75 else
76 return FALSE;
79 boolean
80 is_ice(x, y)
81 int x, y;
83 schar ltyp;
85 if (!isok(x, y))
86 return FALSE;
87 ltyp = levl[x][y].typ;
88 if (ltyp == ICE || (ltyp == DRAWBRIDGE_UP
89 && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE))
90 return TRUE;
91 return FALSE;
94 boolean
95 is_moat(x, y)
96 int x, y;
98 schar ltyp;
100 if (!isok(x, y))
101 return FALSE;
102 ltyp = levl[x][y].typ;
103 if (!Is_juiblex_level(&u.uz)
104 && (ltyp == MOAT
105 || (ltyp == DRAWBRIDGE_UP
106 && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT)))
107 return TRUE;
108 return FALSE;
111 schar
112 db_under_typ(mask)
113 int mask;
115 switch (mask & DB_UNDER) {
116 case DB_ICE:
117 return ICE;
118 case DB_LAVA:
119 return LAVAPOOL;
120 case DB_MOAT:
121 return MOAT;
122 default:
123 return STONE;
128 * We want to know whether a wall (or a door) is the portcullis (passageway)
129 * of an eventual drawbridge.
131 * Return value: the direction of the drawbridge.
135 is_drawbridge_wall(x, y)
136 int x, y;
138 struct rm *lev;
140 lev = &levl[x][y];
141 if (lev->typ != DOOR && lev->typ != DBWALL)
142 return -1;
144 if (IS_DRAWBRIDGE(levl[x + 1][y].typ)
145 && (levl[x + 1][y].drawbridgemask & DB_DIR) == DB_WEST)
146 return DB_WEST;
147 if (IS_DRAWBRIDGE(levl[x - 1][y].typ)
148 && (levl[x - 1][y].drawbridgemask & DB_DIR) == DB_EAST)
149 return DB_EAST;
150 if (IS_DRAWBRIDGE(levl[x][y - 1].typ)
151 && (levl[x][y - 1].drawbridgemask & DB_DIR) == DB_SOUTH)
152 return DB_SOUTH;
153 if (IS_DRAWBRIDGE(levl[x][y + 1].typ)
154 && (levl[x][y + 1].drawbridgemask & DB_DIR) == DB_NORTH)
155 return DB_NORTH;
157 return -1;
161 * Use is_db_wall where you want to verify that a
162 * drawbridge "wall" is UP in the location x, y
163 * (instead of UP or DOWN, as with is_drawbridge_wall).
165 boolean
166 is_db_wall(x, y)
167 int x, y;
169 return (boolean) (levl[x][y].typ == DBWALL);
173 * Return true with x,y pointing to the drawbridge if x,y initially indicate
174 * a drawbridge or drawbridge wall.
176 boolean
177 find_drawbridge(x, y)
178 int *x, *y;
180 int dir;
182 if (IS_DRAWBRIDGE(levl[*x][*y].typ))
183 return TRUE;
184 dir = is_drawbridge_wall(*x, *y);
185 if (dir >= 0) {
186 switch (dir) {
187 case DB_NORTH:
188 (*y)++;
189 break;
190 case DB_SOUTH:
191 (*y)--;
192 break;
193 case DB_EAST:
194 (*x)--;
195 break;
196 case DB_WEST:
197 (*x)++;
198 break;
200 return TRUE;
202 return FALSE;
206 * Find the drawbridge wall associated with a drawbridge.
208 STATIC_OVL void
209 get_wall_for_db(x, y)
210 int *x, *y;
212 switch (levl[*x][*y].drawbridgemask & DB_DIR) {
213 case DB_NORTH:
214 (*y)--;
215 break;
216 case DB_SOUTH:
217 (*y)++;
218 break;
219 case DB_EAST:
220 (*x)++;
221 break;
222 case DB_WEST:
223 (*x)--;
224 break;
229 * Creation of a drawbridge at pos x,y.
230 * dir is the direction.
231 * flag must be put to TRUE if we want the drawbridge to be opened.
234 boolean
235 create_drawbridge(x, y, dir, flag)
236 int x, y, dir;
237 boolean flag;
239 int x2, y2;
240 boolean horiz;
241 boolean lava = levl[x][y].typ == LAVAPOOL; /* assume initialized map */
243 x2 = x;
244 y2 = y;
245 switch (dir) {
246 case DB_NORTH:
247 horiz = TRUE;
248 y2--;
249 break;
250 case DB_SOUTH:
251 horiz = TRUE;
252 y2++;
253 break;
254 case DB_EAST:
255 horiz = FALSE;
256 x2++;
257 break;
258 default:
259 impossible("bad direction in create_drawbridge");
260 /*FALLTHRU*/
261 case DB_WEST:
262 horiz = FALSE;
263 x2--;
264 break;
266 if (!IS_WALL(levl[x2][y2].typ))
267 return FALSE;
268 if (flag) { /* We want the bridge open */
269 levl[x][y].typ = DRAWBRIDGE_DOWN;
270 levl[x2][y2].typ = DOOR;
271 levl[x2][y2].doormask = D_NODOOR;
272 } else {
273 levl[x][y].typ = DRAWBRIDGE_UP;
274 levl[x2][y2].typ = DBWALL;
275 /* Drawbridges are non-diggable. */
276 levl[x2][y2].wall_info = W_NONDIGGABLE;
278 levl[x][y].horizontal = !horiz;
279 levl[x2][y2].horizontal = horiz;
280 levl[x][y].drawbridgemask = dir;
281 if (lava)
282 levl[x][y].drawbridgemask |= DB_LAVA;
283 return TRUE;
286 struct entity {
287 struct monst *emon; /* youmonst for the player */
288 struct permonst *edata; /* must be non-zero for record to be valid */
289 int ex, ey;
292 #define ENTITIES 2
294 static NEARDATA struct entity occupants[ENTITIES];
296 STATIC_OVL
297 struct entity *
298 e_at(x, y)
299 int x, y;
301 int entitycnt;
303 for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++)
304 if ((occupants[entitycnt].edata) && (occupants[entitycnt].ex == x)
305 && (occupants[entitycnt].ey == y))
306 break;
307 debugpline1("entitycnt = %d", entitycnt);
308 #ifdef D_DEBUG
309 wait_synch();
310 #endif
311 return (entitycnt == ENTITIES) ? (struct entity *) 0
312 : &(occupants[entitycnt]);
315 STATIC_OVL void
316 m_to_e(mtmp, x, y, etmp)
317 struct monst *mtmp;
318 int x, y;
319 struct entity *etmp;
321 etmp->emon = mtmp;
322 if (mtmp) {
323 etmp->ex = x;
324 etmp->ey = y;
325 if (mtmp->wormno && (x != mtmp->mx || y != mtmp->my))
326 etmp->edata = &mons[PM_LONG_WORM_TAIL];
327 else
328 etmp->edata = mtmp->data;
329 } else
330 etmp->edata = (struct permonst *) 0;
333 STATIC_OVL void
334 u_to_e(etmp)
335 struct entity *etmp;
337 etmp->emon = &youmonst;
338 etmp->ex = u.ux;
339 etmp->ey = u.uy;
340 etmp->edata = youmonst.data;
343 STATIC_OVL void
344 set_entity(x, y, etmp)
345 int x, y;
346 struct entity *etmp;
348 if ((x == u.ux) && (y == u.uy))
349 u_to_e(etmp);
350 else if (MON_AT(x, y))
351 m_to_e(m_at(x, y), x, y, etmp);
352 else
353 etmp->edata = (struct permonst *) 0;
356 #define is_u(etmp) (etmp->emon == &youmonst)
357 #define e_canseemon(etmp) \
358 (is_u(etmp) ? (boolean) TRUE : canseemon(etmp->emon))
361 * e_strg is a utility routine which is not actually in use anywhere, since
362 * the specialized routines below suffice for all current purposes.
365 /* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */
367 STATIC_OVL const char *
368 e_nam(etmp)
369 struct entity *etmp;
371 return is_u(etmp) ? "you" : mon_nam(etmp->emon);
375 * Generates capitalized entity name, makes 2nd -> 3rd person conversion on
376 * verb, where necessary.
379 STATIC_OVL const char *
380 E_phrase(etmp, verb)
381 struct entity *etmp;
382 const char *verb;
384 static char wholebuf[80];
386 Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon));
387 if (!verb || !*verb)
388 return wholebuf;
389 Strcat(wholebuf, " ");
390 if (is_u(etmp))
391 Strcat(wholebuf, verb);
392 else
393 Strcat(wholebuf, vtense((char *) 0, verb));
394 return wholebuf;
398 * Simple-minded "can it be here?" routine
401 STATIC_OVL boolean
402 e_survives_at(etmp, x, y)
403 struct entity *etmp;
404 int x, y;
406 if (noncorporeal(etmp->edata))
407 return TRUE;
408 if (is_pool(x, y))
409 return (boolean) ((is_u(etmp) && (Wwalking || Amphibious || Swimming
410 || Flying || Levitation))
411 || is_swimmer(etmp->edata)
412 || is_flyer(etmp->edata)
413 || is_floater(etmp->edata));
414 /* must force call to lava_effects in e_died if is_u */
415 if (is_lava(x, y))
416 return (boolean) ((is_u(etmp) && (Levitation || Flying))
417 || likes_lava(etmp->edata)
418 || is_flyer(etmp->edata));
419 if (is_db_wall(x, y))
420 return (boolean) (is_u(etmp) ? Passes_walls
421 : passes_walls(etmp->edata));
422 return TRUE;
425 STATIC_OVL void
426 e_died(etmp, dest, how)
427 struct entity *etmp;
428 int dest, how;
430 if (is_u(etmp)) {
431 if (how == DROWNING) {
432 killer.name[0] = 0; /* drown() sets its own killer */
433 (void) drown();
434 } else if (how == BURNING) {
435 killer.name[0] = 0; /* lava_effects() sets own killer */
436 (void) lava_effects();
437 } else {
438 coord xy;
440 /* use more specific killer if specified */
441 if (!killer.name[0]) {
442 killer.format = KILLED_BY_AN;
443 Strcpy(killer.name, "falling drawbridge");
445 done(how);
446 /* So, you didn't die */
447 if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
448 if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
449 pline("A %s force teleports you away...",
450 Hallucination ? "normal" : "strange");
451 teleds(xy.x, xy.y, FALSE);
453 /* otherwise on top of the drawbridge is the
454 * only viable spot in the dungeon, so stay there
458 /* we might have crawled out of the moat to survive */
459 etmp->ex = u.ux, etmp->ey = u.uy;
460 } else {
461 int entitycnt;
463 killer.name[0] = 0;
464 /* fake "digested to death" damage-type suppresses corpse */
465 #define mk_message(dest) ((dest & 1) ? "" : (char *) 0)
466 #define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS)
467 /* if monsters are moving, one of them caused the destruction */
468 if (context.mon_moving)
469 monkilled(etmp->emon, mk_message(dest), mk_corpse(dest));
470 else /* you caused it */
471 xkilled(etmp->emon, dest);
472 etmp->edata = (struct permonst *) 0;
474 /* dead long worm handling */
475 for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) {
476 if (etmp != &(occupants[entitycnt])
477 && etmp->emon == occupants[entitycnt].emon)
478 occupants[entitycnt].edata = (struct permonst *) 0;
480 #undef mk_message
481 #undef mk_corpse
486 * These are never directly affected by a bridge or portcullis.
489 STATIC_OVL boolean
490 automiss(etmp)
491 struct entity *etmp;
493 return (boolean) ((is_u(etmp) ? Passes_walls : passes_walls(etmp->edata))
494 || noncorporeal(etmp->edata));
498 * Does falling drawbridge or portcullis miss etmp?
501 STATIC_OVL boolean
502 e_missed(etmp, chunks)
503 struct entity *etmp;
504 boolean chunks;
506 int misses;
508 if (chunks) {
509 debugpline0("Do chunks miss?");
511 if (automiss(etmp))
512 return TRUE;
514 if (is_flyer(etmp->edata)
515 && (is_u(etmp) ? !Unaware
516 : (etmp->emon->mcanmove && !etmp->emon->msleeping)))
517 /* flying requires mobility */
518 misses = 5; /* out of 8 */
519 else if (is_floater(etmp->edata)
520 || (is_u(etmp) && Levitation)) /* doesn't require mobility */
521 misses = 3;
522 else if (chunks && is_pool(etmp->ex, etmp->ey))
523 misses = 2; /* sitting ducks */
524 else
525 misses = 0;
527 if (is_db_wall(etmp->ex, etmp->ey))
528 misses -= 3; /* less airspace */
530 debugpline1("Miss chance = %d (out of 8)", misses);
532 return (misses >= rnd(8)) ? TRUE : FALSE;
536 * Can etmp jump from death?
539 STATIC_OVL boolean
540 e_jumps(etmp)
541 struct entity *etmp;
543 int tmp = 4; /* out of 10 */
545 if (is_u(etmp) ? (Unaware || Fumbling)
546 : (!etmp->emon->mcanmove || etmp->emon->msleeping
547 || !etmp->edata->mmove || etmp->emon->wormno))
548 return FALSE;
550 if (is_u(etmp) ? Confusion : etmp->emon->mconf)
551 tmp -= 2;
553 if (is_u(etmp) ? Stunned : etmp->emon->mstun)
554 tmp -= 3;
556 if (is_db_wall(etmp->ex, etmp->ey))
557 tmp -= 2; /* less room to maneuver */
559 debugpline2("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp);
560 return (tmp >= rnd(10)) ? TRUE : FALSE;
563 STATIC_OVL void
564 do_entity(etmp)
565 struct entity *etmp;
567 int newx, newy, at_portcullis, oldx, oldy;
568 boolean must_jump = FALSE, relocates = FALSE, e_inview;
569 struct rm *crm;
571 if (!etmp->edata)
572 return;
574 e_inview = e_canseemon(etmp);
575 oldx = etmp->ex;
576 oldy = etmp->ey;
577 at_portcullis = is_db_wall(oldx, oldy);
578 crm = &levl[oldx][oldy];
580 if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
581 if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
582 pline_The("%s passes through %s!",
583 at_portcullis ? "portcullis" : "drawbridge",
584 e_nam(etmp));
585 if (is_u(etmp))
586 spoteffects(FALSE);
587 return;
589 if (e_missed(etmp, FALSE)) {
590 if (at_portcullis) {
591 pline_The("portcullis misses %s!", e_nam(etmp));
592 } else {
593 debugpline1("The drawbridge misses %s!", e_nam(etmp));
595 if (e_survives_at(etmp, oldx, oldy)) {
596 return;
597 } else {
598 debugpline0("Mon can't survive here");
599 if (at_portcullis)
600 must_jump = TRUE;
601 else
602 relocates = TRUE; /* just ride drawbridge in */
604 } else {
605 if (crm->typ == DRAWBRIDGE_DOWN) {
606 pline("%s crushed underneath the drawbridge.",
607 E_phrase(etmp, "are")); /* no jump */
608 e_died(etmp, e_inview ? 3 : 2, CRUSHING); /* no corpse */
609 return; /* Note: Beyond this point, we know we're */
610 } /* not at an opened drawbridge, since all */
611 must_jump = TRUE; /* *missable* creatures survive on the */
612 } /* square, and all the unmissed ones die. */
613 if (must_jump) {
614 if (at_portcullis) {
615 if (e_jumps(etmp)) {
616 relocates = TRUE;
617 debugpline0("Jump succeeds!");
618 } else {
619 if (e_inview)
620 pline("%s crushed by the falling portcullis!",
621 E_phrase(etmp, "are"));
622 else if (!Deaf)
623 You_hear("a crushing sound.");
624 e_died(etmp, e_inview ? 3 : 2, CRUSHING);
625 /* no corpse */
626 return;
628 } else { /* tries to jump off bridge to original square */
629 relocates = !e_jumps(etmp);
630 debugpline1("Jump %s!", (relocates) ? "fails" : "succeeds");
635 * Here's where we try to do relocation. Assumes that etmp is not
636 * arriving
637 * at the portcullis square while the drawbridge is falling, since this
638 * square
639 * would be inaccessible (i.e. etmp started on drawbridge square) or
640 * unnecessary (i.e. etmp started here) in such a situation.
642 debugpline0("Doing relocation.");
643 newx = oldx;
644 newy = oldy;
645 (void) find_drawbridge(&newx, &newy);
646 if ((newx == oldx) && (newy == oldy))
647 get_wall_for_db(&newx, &newy);
648 debugpline0("Checking new square for occupancy.");
649 if (relocates && (e_at(newx, newy))) {
651 * Standoff problem: one or both entities must die, and/or both
652 * switch
653 * places. Avoid infinite recursion by checking first whether the
654 * other
655 * entity is staying put. Clean up if we happen to move/die in
656 * recursion.
658 struct entity *other;
660 other = e_at(newx, newy);
661 debugpline1("New square is occupied by %s", e_nam(other));
662 if (e_survives_at(other, newx, newy) && automiss(other)) {
663 relocates = FALSE; /* "other" won't budge */
664 debugpline1("%s suicide.", E_phrase(etmp, "commit"));
665 } else {
666 debugpline1("Handling %s", e_nam(other));
667 while ((e_at(newx, newy) != 0) && (e_at(newx, newy) != etmp))
668 do_entity(other);
669 debugpline1("Checking existence of %s", e_nam(etmp));
670 #ifdef D_DEBUG
671 wait_synch();
672 #endif
673 if (e_at(oldx, oldy) != etmp) {
674 debugpline1("%s moved or died in recursion somewhere",
675 E_phrase(etmp, "have"));
676 #ifdef D_DEBUG
677 wait_synch();
678 #endif
679 return;
683 if (relocates && !e_at(newx, newy)) { /* if e_at() entity = worm tail */
684 debugpline1("Moving %s", e_nam(etmp));
685 if (!is_u(etmp)) {
686 remove_monster(etmp->ex, etmp->ey);
687 place_monster(etmp->emon, newx, newy);
688 update_monster_region(etmp->emon);
689 } else {
690 u.ux = newx;
691 u.uy = newy;
693 etmp->ex = newx;
694 etmp->ey = newy;
695 e_inview = e_canseemon(etmp);
697 debugpline1("Final disposition of %s", e_nam(etmp));
698 #ifdef D_DEBUG
699 wait_synch();
700 #endif
701 if (is_db_wall(etmp->ex, etmp->ey)) {
702 debugpline1("%s in portcullis chamber", E_phrase(etmp, "are"));
703 #ifdef D_DEBUG
704 wait_synch();
705 #endif
706 if (e_inview) {
707 if (is_u(etmp)) {
708 You("tumble towards the closed portcullis!");
709 if (automiss(etmp))
710 You("pass through it!");
711 else
712 pline_The("drawbridge closes in...");
713 } else
714 pline("%s behind the drawbridge.",
715 E_phrase(etmp, "disappear"));
717 if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
718 killer.format = KILLED_BY_AN;
719 Strcpy(killer.name, "closing drawbridge");
720 e_died(etmp, 0, CRUSHING); /* no message */
721 return;
723 debugpline1("%s in here", E_phrase(etmp, "survive"));
724 } else {
725 debugpline1("%s on drawbridge square", E_phrase(etmp, "are"));
726 if (is_pool(etmp->ex, etmp->ey) && !e_inview)
727 if (!Deaf)
728 You_hear("a splash.");
729 if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
730 if (e_inview && !is_flyer(etmp->edata)
731 && !is_floater(etmp->edata))
732 pline("%s from the bridge.", E_phrase(etmp, "fall"));
733 return;
735 debugpline1("%s cannot survive on the drawbridge square",
736 E_phrase(etmp, NULL));
737 if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey))
738 if (e_inview && !is_u(etmp)) {
739 /* drown() will supply msgs if nec. */
740 boolean lava = is_lava(etmp->ex, etmp->ey);
742 if (Hallucination)
743 pline("%s the %s and disappears.",
744 E_phrase(etmp, "drink"), lava ? "lava" : "moat");
745 else
746 pline("%s into the %s.", E_phrase(etmp, "fall"),
747 lava ? "lava" : "moat");
749 killer.format = NO_KILLER_PREFIX;
750 Strcpy(killer.name, "fell from a drawbridge");
751 e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */
752 (is_pool(etmp->ex, etmp->ey))
753 ? DROWNING
754 : (is_lava(etmp->ex, etmp->ey)) ? BURNING
755 : CRUSHING); /*no corpse*/
756 return;
761 * Close the drawbridge located at x,y
764 void
765 close_drawbridge(x, y)
766 int x, y;
768 register struct rm *lev1, *lev2;
769 struct trap *t;
770 int x2, y2;
772 lev1 = &levl[x][y];
773 if (lev1->typ != DRAWBRIDGE_DOWN)
774 return;
775 x2 = x;
776 y2 = y;
777 get_wall_for_db(&x2, &y2);
778 if (cansee(x, y) || cansee(x2, y2))
779 You_see("a drawbridge %s up!",
780 (((u.ux == x || u.uy == y) && !Underwater)
781 || distu(x2, y2) < distu(x, y))
782 ? "coming"
783 : "going");
784 else /* "5 gears turn" for castle drawbridge tune */
785 You_hear("chains rattling and gears turning.");
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;
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) && !Deaf)
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)
812 deltrap(t);
813 if ((t = t_at(x2, y2)) != 0)
814 deltrap(t);
815 del_engr_at(x, y);
816 del_engr_at(x2, y2);
817 newsym(x, y);
818 newsym(x2, y2);
819 block_point(x2, y2); /* vision */
823 * Open the drawbridge located at x,y
826 void
827 open_drawbridge(x, y)
828 int x, y;
830 register struct rm *lev1, *lev2;
831 struct trap *t;
832 int x2, y2;
834 lev1 = &levl[x][y];
835 if (lev1->typ != DRAWBRIDGE_UP)
836 return;
837 x2 = x;
838 y2 = y;
839 get_wall_for_db(&x2, &y2);
840 if (cansee(x, y) || cansee(x2, y2))
841 You_see("a drawbridge %s down!",
842 (distu(x2, y2) < distu(x, y)) ? "going" : "coming");
843 else /* "5 gears turn" for castle drawbridge tune */
844 You_hear("gears turning and chains rattling.");
845 lev1->typ = DRAWBRIDGE_DOWN;
846 lev2 = &levl[x2][y2];
847 lev2->typ = DOOR;
848 lev2->doormask = D_NODOOR;
849 set_entity(x, y, &(occupants[0]));
850 set_entity(x2, y2, &(occupants[1]));
851 do_entity(&(occupants[0])); /* do set_entity after first */
852 set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */
853 do_entity(&(occupants[1]));
854 (void) revive_nasty(x, y, (char *) 0);
855 delallobj(x, y);
856 if ((t = t_at(x, y)) != 0)
857 deltrap(t);
858 if ((t = t_at(x2, y2)) != 0)
859 deltrap(t);
860 del_engr_at(x, y);
861 del_engr_at(x2, y2);
862 newsym(x, y);
863 newsym(x2, y2);
864 unblock_point(x2, y2); /* vision */
865 if (Is_stronghold(&u.uz))
866 u.uevent.uopened_dbridge = TRUE;
870 * Let's destroy the drawbridge located at x,y
873 void
874 destroy_drawbridge(x, y)
875 int x, y;
877 register struct rm *lev1, *lev2;
878 struct trap *t;
879 struct obj *otmp;
880 int x2, y2, i;
881 boolean e_inview;
882 struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]);
884 lev1 = &levl[x][y];
885 if (!IS_DRAWBRIDGE(lev1->typ))
886 return;
887 x2 = x;
888 y2 = y;
889 get_wall_for_db(&x2, &y2);
890 lev2 = &levl[x2][y2];
891 if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT
892 || (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) {
893 struct obj *otmp2;
894 boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA;
895 if (lev1->typ == DRAWBRIDGE_UP) {
896 if (cansee(x2, y2))
897 pline_The("portcullis of the drawbridge falls into the %s!",
898 lava ? "lava" : "moat");
899 else if (!Deaf)
900 You_hear("a loud *SPLASH*!");
901 } else {
902 if (cansee(x, y))
903 pline_The("drawbridge collapses into the %s!",
904 lava ? "lava" : "moat");
905 else if (!Deaf)
906 You_hear("a loud *SPLASH*!");
908 lev1->typ = lava ? LAVAPOOL : MOAT;
909 lev1->drawbridgemask = 0;
910 if ((otmp2 = sobj_at(BOULDER, x, y)) != 0) {
911 obj_extract_self(otmp2);
912 (void) flooreffects(otmp2, x, y, "fall");
914 } else {
915 if (cansee(x, y))
916 pline_The("drawbridge disintegrates!");
917 else
918 You_hear("a loud *CRASH*!");
919 lev1->typ = ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM);
920 lev1->icedpool = ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0);
922 wake_nearto(x, y, 500);
923 lev2->typ = DOOR;
924 lev2->doormask = D_NODOOR;
925 if ((t = t_at(x, y)) != 0)
926 deltrap(t);
927 if ((t = t_at(x2, y2)) != 0)
928 deltrap(t);
929 del_engr_at(x, y);
930 del_engr_at(x2, y2);
931 for (i = rn2(6); i > 0; --i) { /* scatter some debris */
932 /* doesn't matter if we happen to pick <x,y2> or <x2,y>;
933 since drawbridges are never placed diagonally, those
934 pairings will always match one of <x,y> or <x2,y2> */
935 otmp = mksobj_at(IRON_CHAIN, rn2(2) ? x : x2, rn2(2) ? y : y2, TRUE,
936 FALSE);
937 /* a force of 5 here would yield a radius of 2 for
938 iron chain; anything less produces a radius of 1 */
939 (void) scatter(otmp->ox, otmp->oy, 1, MAY_HIT, otmp);
941 newsym(x, y);
942 newsym(x2, y2);
943 if (!does_block(x2, y2, lev2))
944 unblock_point(x2, y2); /* vision */
945 if (Is_stronghold(&u.uz))
946 u.uevent.uopened_dbridge = TRUE;
948 set_entity(x2, y2, etmp2); /* currently only automissers can be here */
949 if (etmp2->edata) {
950 e_inview = e_canseemon(etmp2);
951 if (!automiss(etmp2)) {
952 if (e_inview)
953 pline("%s blown apart by flying debris.",
954 E_phrase(etmp2, "are"));
955 killer.format = KILLED_BY_AN;
956 Strcpy(killer.name, "exploding drawbridge");
957 e_died(etmp2, e_inview ? 3 : 2, CRUSHING); /*no corpse*/
958 } /* nothing which is vulnerable can survive this */
960 set_entity(x, y, etmp1);
961 if (etmp1->edata) {
962 e_inview = e_canseemon(etmp1);
963 if (e_missed(etmp1, TRUE)) {
964 debugpline1("%s spared!", E_phrase(etmp1, "are"));
965 /* if there is water or lava here, fall in now */
966 if (is_u(etmp1))
967 spoteffects(FALSE);
968 else
969 (void) minliquid(etmp1->emon);
970 } else {
971 if (e_inview) {
972 if (!is_u(etmp1) && Hallucination)
973 pline("%s into some heavy metal!",
974 E_phrase(etmp1, "get"));
975 else
976 pline("%s hit by a huge chunk of metal!",
977 E_phrase(etmp1, "are"));
978 } else {
979 if (!Deaf && !is_u(etmp1) && !is_pool(x, y)) {
980 You_hear("a crushing sound.");
981 } else {
982 debugpline1("%s from shrapnel", E_phrase(etmp1, "die"));
985 killer.format = KILLED_BY_AN;
986 Strcpy(killer.name, "collapsing drawbridge");
987 e_died(etmp1, e_inview ? 3 : 2, CRUSHING); /*no corpse*/
988 if (levl[etmp1->ex][etmp1->ey].typ == MOAT)
989 do_entity(etmp1);
994 /*dbridge.c*/