NetHack->aNetHack
[aNetHack.git] / src / dbridge.c
blob0d0421862f01f81dc2038b51e169f8ea9c474ff4
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, xkill_flags, how)
427 struct entity *etmp;
428 int xkill_flags, 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 & XKILL_NOMSG) != 0) ? (char *) 0 : "")
466 #define mk_corpse(dest) (((dest & XKILL_NOCORPSE) != 0) ? AD_DGST : AD_PHYS)
467 /* if monsters are moving, one of them caused the destruction */
468 if (context.mon_moving)
469 monkilled(etmp->emon,
470 mk_message(xkill_flags), mk_corpse(xkill_flags));
471 else /* you caused it */
472 xkilled(etmp->emon, xkill_flags);
473 etmp->edata = (struct permonst *) 0;
475 /* dead long worm handling */
476 for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) {
477 if (etmp != &(occupants[entitycnt])
478 && etmp->emon == occupants[entitycnt].emon)
479 occupants[entitycnt].edata = (struct permonst *) 0;
481 #undef mk_message
482 #undef mk_corpse
487 * These are never directly affected by a bridge or portcullis.
490 STATIC_OVL boolean
491 automiss(etmp)
492 struct entity *etmp;
494 return (boolean) ((is_u(etmp) ? Passes_walls : passes_walls(etmp->edata))
495 || noncorporeal(etmp->edata));
499 * Does falling drawbridge or portcullis miss etmp?
502 STATIC_OVL boolean
503 e_missed(etmp, chunks)
504 struct entity *etmp;
505 boolean chunks;
507 int misses;
509 if (chunks) {
510 debugpline0("Do chunks miss?");
512 if (automiss(etmp))
513 return TRUE;
515 if (is_flyer(etmp->edata)
516 && (is_u(etmp) ? !Unaware
517 : (etmp->emon->mcanmove && !etmp->emon->msleeping)))
518 /* flying requires mobility */
519 misses = 5; /* out of 8 */
520 else if (is_floater(etmp->edata)
521 || (is_u(etmp) && Levitation)) /* doesn't require mobility */
522 misses = 3;
523 else if (chunks && is_pool(etmp->ex, etmp->ey))
524 misses = 2; /* sitting ducks */
525 else
526 misses = 0;
528 if (is_db_wall(etmp->ex, etmp->ey))
529 misses -= 3; /* less airspace */
531 debugpline1("Miss chance = %d (out of 8)", misses);
533 return (misses >= rnd(8)) ? TRUE : FALSE;
537 * Can etmp jump from death?
540 STATIC_OVL boolean
541 e_jumps(etmp)
542 struct entity *etmp;
544 int tmp = 4; /* out of 10 */
546 if (is_u(etmp) ? (Unaware || Fumbling)
547 : (!etmp->emon->mcanmove || etmp->emon->msleeping
548 || !etmp->edata->mmove || etmp->emon->wormno))
549 return FALSE;
551 if (is_u(etmp) ? Confusion : etmp->emon->mconf)
552 tmp -= 2;
554 if (is_u(etmp) ? Stunned : etmp->emon->mstun)
555 tmp -= 3;
557 if (is_db_wall(etmp->ex, etmp->ey))
558 tmp -= 2; /* less room to maneuver */
560 debugpline2("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp);
561 return (tmp >= rnd(10)) ? TRUE : FALSE;
564 STATIC_OVL void
565 do_entity(etmp)
566 struct entity *etmp;
568 int newx, newy, at_portcullis, oldx, oldy;
569 boolean must_jump = FALSE, relocates = FALSE, e_inview;
570 struct rm *crm;
572 if (!etmp->edata)
573 return;
575 e_inview = e_canseemon(etmp);
576 oldx = etmp->ex;
577 oldy = etmp->ey;
578 at_portcullis = is_db_wall(oldx, oldy);
579 crm = &levl[oldx][oldy];
581 if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
582 if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
583 pline_The("%s passes through %s!",
584 at_portcullis ? "portcullis" : "drawbridge",
585 e_nam(etmp));
586 if (is_u(etmp))
587 spoteffects(FALSE);
588 return;
590 if (e_missed(etmp, FALSE)) {
591 if (at_portcullis) {
592 pline_The("portcullis misses %s!", e_nam(etmp));
593 } else {
594 debugpline1("The drawbridge misses %s!", e_nam(etmp));
596 if (e_survives_at(etmp, oldx, oldy)) {
597 return;
598 } else {
599 debugpline0("Mon can't survive here");
600 if (at_portcullis)
601 must_jump = TRUE;
602 else
603 relocates = TRUE; /* just ride drawbridge in */
605 } else {
606 if (crm->typ == DRAWBRIDGE_DOWN) {
607 pline("%s crushed underneath the drawbridge.",
608 E_phrase(etmp, "are")); /* no jump */
609 e_died(etmp,
610 XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
611 CRUSHING); /* no corpse */
612 return; /* Note: Beyond this point, we know we're */
613 } /* not at an opened drawbridge, since all */
614 must_jump = TRUE; /* *missable* creatures survive on the */
615 } /* square, and all the unmissed ones die. */
616 if (must_jump) {
617 if (at_portcullis) {
618 if (e_jumps(etmp)) {
619 relocates = TRUE;
620 debugpline0("Jump succeeds!");
621 } else {
622 if (e_inview)
623 pline("%s crushed by the falling portcullis!",
624 E_phrase(etmp, "are"));
625 else if (!Deaf)
626 You_hear("a crushing sound.");
627 e_died(etmp,
628 XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG
629 : XKILL_NOMSG),
630 CRUSHING);
631 /* no corpse */
632 return;
634 } else { /* tries to jump off bridge to original square */
635 relocates = !e_jumps(etmp);
636 debugpline1("Jump %s!", (relocates) ? "fails" : "succeeds");
641 * Here's where we try to do relocation. Assumes that etmp is not
642 * arriving
643 * at the portcullis square while the drawbridge is falling, since this
644 * square
645 * would be inaccessible (i.e. etmp started on drawbridge square) or
646 * unnecessary (i.e. etmp started here) in such a situation.
648 debugpline0("Doing relocation.");
649 newx = oldx;
650 newy = oldy;
651 (void) find_drawbridge(&newx, &newy);
652 if ((newx == oldx) && (newy == oldy))
653 get_wall_for_db(&newx, &newy);
654 debugpline0("Checking new square for occupancy.");
655 if (relocates && (e_at(newx, newy))) {
657 * Standoff problem: one or both entities must die, and/or both
658 * switch
659 * places. Avoid infinite recursion by checking first whether the
660 * other
661 * entity is staying put. Clean up if we happen to move/die in
662 * recursion.
664 struct entity *other;
666 other = e_at(newx, newy);
667 debugpline1("New square is occupied by %s", e_nam(other));
668 if (e_survives_at(other, newx, newy) && automiss(other)) {
669 relocates = FALSE; /* "other" won't budge */
670 debugpline1("%s suicide.", E_phrase(etmp, "commit"));
671 } else {
672 debugpline1("Handling %s", e_nam(other));
673 while ((e_at(newx, newy) != 0) && (e_at(newx, newy) != etmp))
674 do_entity(other);
675 debugpline1("Checking existence of %s", e_nam(etmp));
676 #ifdef D_DEBUG
677 wait_synch();
678 #endif
679 if (e_at(oldx, oldy) != etmp) {
680 debugpline1("%s moved or died in recursion somewhere",
681 E_phrase(etmp, "have"));
682 #ifdef D_DEBUG
683 wait_synch();
684 #endif
685 return;
689 if (relocates && !e_at(newx, newy)) { /* if e_at() entity = worm tail */
690 debugpline1("Moving %s", e_nam(etmp));
691 if (!is_u(etmp)) {
692 remove_monster(etmp->ex, etmp->ey);
693 place_monster(etmp->emon, newx, newy);
694 update_monster_region(etmp->emon);
695 } else {
696 u.ux = newx;
697 u.uy = newy;
699 etmp->ex = newx;
700 etmp->ey = newy;
701 e_inview = e_canseemon(etmp);
703 debugpline1("Final disposition of %s", e_nam(etmp));
704 #ifdef D_DEBUG
705 wait_synch();
706 #endif
707 if (is_db_wall(etmp->ex, etmp->ey)) {
708 debugpline1("%s in portcullis chamber", E_phrase(etmp, "are"));
709 #ifdef D_DEBUG
710 wait_synch();
711 #endif
712 if (e_inview) {
713 if (is_u(etmp)) {
714 You("tumble towards the closed portcullis!");
715 if (automiss(etmp))
716 You("pass through it!");
717 else
718 pline_The("drawbridge closes in...");
719 } else
720 pline("%s behind the drawbridge.",
721 E_phrase(etmp, "disappear"));
723 if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
724 killer.format = KILLED_BY_AN;
725 Strcpy(killer.name, "closing drawbridge");
726 e_died(etmp, XKILL_NOMSG, CRUSHING);
727 return;
729 debugpline1("%s in here", E_phrase(etmp, "survive"));
730 } else {
731 debugpline1("%s on drawbridge square", E_phrase(etmp, "are"));
732 if (is_pool(etmp->ex, etmp->ey) && !e_inview)
733 if (!Deaf)
734 You_hear("a splash.");
735 if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
736 if (e_inview && !is_flyer(etmp->edata)
737 && !is_floater(etmp->edata))
738 pline("%s from the bridge.", E_phrase(etmp, "fall"));
739 return;
741 debugpline1("%s cannot survive on the drawbridge square",
742 E_phrase(etmp, NULL));
743 if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey))
744 if (e_inview && !is_u(etmp)) {
745 /* drown() will supply msgs if nec. */
746 boolean lava = is_lava(etmp->ex, etmp->ey);
748 if (Hallucination)
749 pline("%s the %s and disappears.",
750 E_phrase(etmp, "drink"), lava ? "lava" : "moat");
751 else
752 pline("%s into the %s.", E_phrase(etmp, "fall"),
753 lava ? hliquid("lava") : "moat");
755 killer.format = NO_KILLER_PREFIX;
756 Strcpy(killer.name, "fell from a drawbridge");
757 e_died(etmp, /* CRUSHING is arbitrary */
758 XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
759 is_pool(etmp->ex, etmp->ey) ? DROWNING
760 : is_lava(etmp->ex, etmp->ey) ? BURNING
761 : CRUSHING); /*no corpse*/
762 return;
767 * Close the drawbridge located at x,y
770 void
771 close_drawbridge(x, y)
772 int x, y;
774 register struct rm *lev1, *lev2;
775 struct trap *t;
776 int x2, y2;
778 lev1 = &levl[x][y];
779 if (lev1->typ != DRAWBRIDGE_DOWN)
780 return;
781 x2 = x;
782 y2 = y;
783 get_wall_for_db(&x2, &y2);
784 if (cansee(x, y) || cansee(x2, y2))
785 You_see("a drawbridge %s up!",
786 (((u.ux == x || u.uy == y) && !Underwater)
787 || distu(x2, y2) < distu(x, y))
788 ? "coming"
789 : "going");
790 else /* "5 gears turn" for castle drawbridge tune */
791 You_hear("chains rattling and gears turning.");
792 lev1->typ = DRAWBRIDGE_UP;
793 lev2 = &levl[x2][y2];
794 lev2->typ = DBWALL;
795 switch (lev1->drawbridgemask & DB_DIR) {
796 case DB_NORTH:
797 case DB_SOUTH:
798 lev2->horizontal = TRUE;
799 break;
800 case DB_WEST:
801 case DB_EAST:
802 lev2->horizontal = FALSE;
803 break;
805 lev2->wall_info = W_NONDIGGABLE;
806 set_entity(x, y, &(occupants[0]));
807 set_entity(x2, y2, &(occupants[1]));
808 do_entity(&(occupants[0])); /* Do set_entity after first */
809 set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */
810 do_entity(&(occupants[1]));
811 if (OBJ_AT(x, y) && !Deaf)
812 You_hear("smashing and crushing.");
813 (void) revive_nasty(x, y, (char *) 0);
814 (void) revive_nasty(x2, y2, (char *) 0);
815 delallobj(x, y);
816 delallobj(x2, y2);
817 if ((t = t_at(x, y)) != 0)
818 deltrap(t);
819 if ((t = t_at(x2, y2)) != 0)
820 deltrap(t);
821 del_engr_at(x, y);
822 del_engr_at(x2, y2);
823 newsym(x, y);
824 newsym(x2, y2);
825 block_point(x2, y2); /* vision */
829 * Open the drawbridge located at x,y
832 void
833 open_drawbridge(x, y)
834 int x, y;
836 register struct rm *lev1, *lev2;
837 struct trap *t;
838 int x2, y2;
840 lev1 = &levl[x][y];
841 if (lev1->typ != DRAWBRIDGE_UP)
842 return;
843 x2 = x;
844 y2 = y;
845 get_wall_for_db(&x2, &y2);
846 if (cansee(x, y) || cansee(x2, y2))
847 You_see("a drawbridge %s down!",
848 (distu(x2, y2) < distu(x, y)) ? "going" : "coming");
849 else /* "5 gears turn" for castle drawbridge tune */
850 You_hear("gears turning and chains rattling.");
851 lev1->typ = DRAWBRIDGE_DOWN;
852 lev2 = &levl[x2][y2];
853 lev2->typ = DOOR;
854 lev2->doormask = D_NODOOR;
855 set_entity(x, y, &(occupants[0]));
856 set_entity(x2, y2, &(occupants[1]));
857 do_entity(&(occupants[0])); /* do set_entity after first */
858 set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */
859 do_entity(&(occupants[1]));
860 (void) revive_nasty(x, y, (char *) 0);
861 delallobj(x, y);
862 if ((t = t_at(x, y)) != 0)
863 deltrap(t);
864 if ((t = t_at(x2, y2)) != 0)
865 deltrap(t);
866 del_engr_at(x, y);
867 del_engr_at(x2, y2);
868 newsym(x, y);
869 newsym(x2, y2);
870 unblock_point(x2, y2); /* vision */
871 if (Is_stronghold(&u.uz))
872 u.uevent.uopened_dbridge = TRUE;
876 * Let's destroy the drawbridge located at x,y
879 void
880 destroy_drawbridge(x, y)
881 int x, y;
883 register struct rm *lev1, *lev2;
884 struct trap *t;
885 struct obj *otmp;
886 int x2, y2, i;
887 boolean e_inview;
888 struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]);
890 lev1 = &levl[x][y];
891 if (!IS_DRAWBRIDGE(lev1->typ))
892 return;
893 x2 = x;
894 y2 = y;
895 get_wall_for_db(&x2, &y2);
896 lev2 = &levl[x2][y2];
897 if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT
898 || (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) {
899 struct obj *otmp2;
900 boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA;
901 if (lev1->typ == DRAWBRIDGE_UP) {
902 if (cansee(x2, y2))
903 pline_The("portcullis of the drawbridge falls into the %s!",
904 lava ? hliquid("lava") : "moat");
905 else if (!Deaf)
906 You_hear("a loud *SPLASH*!");
907 } else {
908 if (cansee(x, y))
909 pline_The("drawbridge collapses into the %s!",
910 lava ? hliquid("lava") : "moat");
911 else if (!Deaf)
912 You_hear("a loud *SPLASH*!");
914 lev1->typ = lava ? LAVAPOOL : MOAT;
915 lev1->drawbridgemask = 0;
916 if ((otmp2 = sobj_at(BOULDER, x, y)) != 0) {
917 obj_extract_self(otmp2);
918 (void) flooreffects(otmp2, x, y, "fall");
920 } else {
921 if (cansee(x, y))
922 pline_The("drawbridge disintegrates!");
923 else
924 You_hear("a loud *CRASH*!");
925 lev1->typ = ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM);
926 lev1->icedpool = ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0);
928 wake_nearto(x, y, 500);
929 lev2->typ = DOOR;
930 lev2->doormask = D_NODOOR;
931 if ((t = t_at(x, y)) != 0)
932 deltrap(t);
933 if ((t = t_at(x2, y2)) != 0)
934 deltrap(t);
935 del_engr_at(x, y);
936 del_engr_at(x2, y2);
937 for (i = rn2(6); i > 0; --i) { /* scatter some debris */
938 /* doesn't matter if we happen to pick <x,y2> or <x2,y>;
939 since drawbridges are never placed diagonally, those
940 pairings will always match one of <x,y> or <x2,y2> */
941 otmp = mksobj_at(IRON_CHAIN, rn2(2) ? x : x2, rn2(2) ? y : y2, TRUE,
942 FALSE);
943 /* a force of 5 here would yield a radius of 2 for
944 iron chain; anything less produces a radius of 1 */
945 (void) scatter(otmp->ox, otmp->oy, 1, MAY_HIT, otmp);
947 newsym(x, y);
948 newsym(x2, y2);
949 if (!does_block(x2, y2, lev2))
950 unblock_point(x2, y2); /* vision */
951 if (Is_stronghold(&u.uz))
952 u.uevent.uopened_dbridge = TRUE;
954 set_entity(x2, y2, etmp2); /* currently only automissers can be here */
955 if (etmp2->edata) {
956 e_inview = e_canseemon(etmp2);
957 if (!automiss(etmp2)) {
958 if (e_inview)
959 pline("%s blown apart by flying debris.",
960 E_phrase(etmp2, "are"));
961 killer.format = KILLED_BY_AN;
962 Strcpy(killer.name, "exploding drawbridge");
963 e_died(etmp2,
964 XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
965 CRUSHING); /*no corpse*/
966 } /* nothing which is vulnerable can survive this */
968 set_entity(x, y, etmp1);
969 if (etmp1->edata) {
970 e_inview = e_canseemon(etmp1);
971 if (e_missed(etmp1, TRUE)) {
972 debugpline1("%s spared!", E_phrase(etmp1, "are"));
973 /* if there is water or lava here, fall in now */
974 if (is_u(etmp1))
975 spoteffects(FALSE);
976 else
977 (void) minliquid(etmp1->emon);
978 } else {
979 if (e_inview) {
980 if (!is_u(etmp1) && Hallucination)
981 pline("%s into some heavy metal!",
982 E_phrase(etmp1, "get"));
983 else
984 pline("%s hit by a huge chunk of metal!",
985 E_phrase(etmp1, "are"));
986 } else {
987 if (!Deaf && !is_u(etmp1) && !is_pool(x, y)) {
988 You_hear("a crushing sound.");
989 } else {
990 debugpline1("%s from shrapnel", E_phrase(etmp1, "die"));
993 killer.format = KILLED_BY_AN;
994 Strcpy(killer.name, "collapsing drawbridge");
995 e_died(etmp1,
996 XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
997 CRUSHING); /*no corpse*/
998 if (levl[etmp1->ex][etmp1->ey].typ == MOAT)
999 do_entity(etmp1);
1004 /*dbridge.c*/