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. */
6 * This file contains the drawbridge manipulation (create, open, close,
9 * Added comprehensive monster-handling, and the "entity" structure to
10 * deal with players as well. - 11/89
16 STATIC_DCL
void get_wall_for_db(int *, int *);
17 STATIC_DCL
struct entity
*e_at(int, int);
18 STATIC_DCL
void m_to_e(struct monst
*, int, int, struct entity
*);
19 STATIC_DCL
void u_to_e(struct entity
*);
20 STATIC_DCL
void set_entity(int, int, struct entity
*);
21 STATIC_DCL
const char *e_nam(struct entity
*);
23 static const char *Enam(struct entity
*); /* unused */
25 STATIC_DCL
const char *E_phrase(struct entity
*, const char *);
26 STATIC_DCL boolean
e_survives_at(struct entity
*, int, int);
27 STATIC_DCL
void e_died(struct entity
*, int, int);
28 STATIC_DCL boolean
automiss(struct entity
*);
29 STATIC_DCL boolean
e_missed(struct entity
*, BOOLEAN_P
);
30 STATIC_DCL boolean
e_jumps(struct entity
*);
31 STATIC_DCL
void do_entity(struct entity
*);
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
;
56 if (!isok(x
,y
)) return FALSE
;
57 ltyp
= levl
[x
][y
].typ
;
58 if (ltyp
== POOL
|| ltyp
== MOAT
|| ltyp
== WATER
|| ltyp
== CRYSTALWATER
|| ltyp
== MOORLAND
|| ltyp
== URINELAKE
) return TRUE
;
59 if (ltyp
== DRAWBRIDGE_UP
&&
60 (levl
[x
][y
].drawbridgemask
& DB_UNDER
) == DB_MOAT
) return TRUE
;
70 if (!isok(x
,y
)) return FALSE
;
71 ltyp
= levl
[x
][y
].typ
;
72 if (ltyp
== POOL
|| ltyp
== MOAT
|| ltyp
== WATER
|| ltyp
== CRYSTALWATER
|| ltyp
== WATERTUNNEL
) return TRUE
;
73 if (ltyp
== DRAWBRIDGE_UP
&&
74 (levl
[x
][y
].drawbridgemask
& DB_UNDER
) == DB_MOAT
) return TRUE
;
84 if (!isok(x
,y
)) return FALSE
;
85 ltyp
= levl
[x
][y
].typ
;
87 || (ltyp
== DRAWBRIDGE_UP
88 && (levl
[x
][y
].drawbridgemask
& DB_UNDER
) == DB_LAVA
)) return TRUE
;
98 if (!isok(x
,y
)) return FALSE
;
99 ltyp
= levl
[x
][y
].typ
;
100 if (ltyp
== WATERTUNNEL
) return TRUE
;
110 if (!isok(x
,y
)) return FALSE
;
111 ltyp
= levl
[x
][y
].typ
;
112 if (ltyp
== CRYSTALWATER
) return TRUE
;
122 if (!isok(x
,y
)) return FALSE
;
123 ltyp
= levl
[x
][y
].typ
;
124 if (ltyp
== MOORLAND
) return TRUE
;
134 if (!isok(x
,y
)) return FALSE
;
135 ltyp
= levl
[x
][y
].typ
;
136 if (ltyp
== PAVEDFLOOR
) return TRUE
;
146 if (!isok(x
,y
)) return FALSE
;
147 ltyp
= levl
[x
][y
].typ
;
148 if (ltyp
== HIGHWAY
) return TRUE
;
158 if (!isok(x
,y
)) return FALSE
;
159 ltyp
= levl
[x
][y
].typ
;
160 if (ltyp
== URINELAKE
) return TRUE
;
170 if (!isok(x
,y
)) return FALSE
;
171 ltyp
= levl
[x
][y
].typ
;
172 if (ltyp
== SHIFTINGSAND
) return TRUE
;
182 if (!isok(x
,y
)) return FALSE
;
183 ltyp
= levl
[x
][y
].typ
;
184 if (ltyp
== STYXRIVER
) return TRUE
;
194 if (!isok(x
,y
)) return FALSE
;
195 ltyp
= levl
[x
][y
].typ
;
196 if (ltyp
== WAGON
) return TRUE
;
206 if (!isok(x
,y
)) return FALSE
;
207 ltyp
= levl
[x
][y
].typ
;
208 if (ltyp
== BURNINGWAGON
) return TRUE
;
218 if (!isok(x
,y
)) return FALSE
;
219 ltyp
= levl
[x
][y
].typ
;
220 if (ltyp
== WELL
) return TRUE
;
230 if (!isok(x
,y
)) return FALSE
;
231 ltyp
= levl
[x
][y
].typ
;
232 if (ltyp
== POISONEDWELL
) return TRUE
;
242 if (!isok(x
,y
)) return FALSE
;
243 ltyp
= levl
[x
][y
].typ
;
244 if (ltyp
== PENTAGRAM
) return TRUE
;
254 if (!isok(x
,y
)) return FALSE
;
255 ltyp
= levl
[x
][y
].typ
;
256 if (ltyp
== CARVEDBED
) return TRUE
;
266 if (!isok(x
,y
)) return FALSE
;
267 ltyp
= levl
[x
][y
].typ
;
268 if (ltyp
== WOODENTABLE
) return TRUE
;
273 isimportantlocation(x
,y
)
278 if (!isok(x
,y
)) return FALSE
;
279 ltyp
= levl
[x
][y
].typ
;
280 if (ltyp
== STAIRS
) return TRUE
;
281 if (invocation_pos(x
, y
)) return TRUE
;
291 if (!isok(x
,y
)) return FALSE
;
292 ltyp
= levl
[x
][y
].typ
;
293 if (ltyp
== STRAWMATTRESS
) return TRUE
;
303 if (!isok(x
,y
)) return FALSE
;
304 ltyp
= levl
[x
][y
].typ
;
305 if (ltyp
== NETHERMIST
) return TRUE
;
315 if (!isok(x
,y
)) return FALSE
;
316 ltyp
= levl
[x
][y
].typ
;
317 if (ltyp
== STALACTITE
) return TRUE
;
327 if (!isok(x
,y
)) return FALSE
;
328 ltyp
= levl
[x
][y
].typ
;
329 if (ltyp
== RAINCLOUD
) return TRUE
;
339 if (!isok(x
,y
)) return FALSE
;
340 ltyp
= levl
[x
][y
].typ
;
341 if (ltyp
== BUBBLES
) return TRUE
;
351 if (!isok(x
,y
)) return FALSE
;
352 ltyp
= levl
[x
][y
].typ
;
353 if (ltyp
== ASH
) return TRUE
;
363 if (!isok(x
,y
)) return FALSE
;
364 ltyp
= levl
[x
][y
].typ
;
365 if (ltyp
== SAND
) return TRUE
;
375 if (!isok(x
,y
)) return FALSE
;
376 ltyp
= levl
[x
][y
].typ
;
377 if (ltyp
== FARMLAND
) return TRUE
;
387 if (!isok(x
,y
)) return FALSE
;
388 ltyp
= levl
[x
][y
].typ
;
389 if (ltyp
== GRASSLAND
) return TRUE
;
399 if (!isok(x
,y
)) return FALSE
;
400 ltyp
= levl
[x
][y
].typ
;
401 if (ltyp
== SNOW
) return TRUE
;
411 if (!isok(x
,y
)) return FALSE
;
412 ltyp
= levl
[x
][y
].typ
;
414 || (ltyp
== DRAWBRIDGE_UP
415 && (levl
[x
][y
].drawbridgemask
& DB_UNDER
) == DB_ICE
)) return TRUE
;
424 * We want to know whether a wall (or a door) is the portcullis (passageway)
425 * of an eventual drawbridge.
427 * Return value: the direction of the drawbridge.
431 is_drawbridge_wall(x
,y
)
437 if (lev
->typ
!= DOOR
&& lev
->typ
!= DBWALL
)
440 if (IS_DRAWBRIDGE(levl
[x
+1][y
].typ
) &&
441 (levl
[x
+1][y
].drawbridgemask
& DB_DIR
) == DB_WEST
)
443 if (IS_DRAWBRIDGE(levl
[x
-1][y
].typ
) &&
444 (levl
[x
-1][y
].drawbridgemask
& DB_DIR
) == DB_EAST
)
446 if (IS_DRAWBRIDGE(levl
[x
][y
-1].typ
) &&
447 (levl
[x
][y
-1].drawbridgemask
& DB_DIR
) == DB_SOUTH
)
449 if (IS_DRAWBRIDGE(levl
[x
][y
+1].typ
) &&
450 (levl
[x
][y
+1].drawbridgemask
& DB_DIR
) == DB_NORTH
)
457 * Use is_db_wall where you want to verify that a
458 * drawbridge "wall" is UP in the location x, y
459 * (instead of UP or DOWN, as with is_drawbridge_wall).
465 return((boolean
)( levl
[x
][y
].typ
== DBWALL
));
470 * Return true with x,y pointing to the drawbridge if x,y initially indicate
471 * a drawbridge or drawbridge wall.
479 if (IS_DRAWBRIDGE(levl
[*x
][*y
].typ
))
481 dir
= is_drawbridge_wall(*x
,*y
);
484 case DB_NORTH
: (*y
)++; break;
485 case DB_SOUTH
: (*y
)--; break;
486 case DB_EAST
: (*x
)--; break;
487 case DB_WEST
: (*x
)++; break;
498 * Find the drawbridge wall associated with a drawbridge.
504 switch (levl
[*x
][*y
].drawbridgemask
& DB_DIR
) {
505 case DB_NORTH
: (*y
)--; break;
506 case DB_SOUTH
: (*y
)++; break;
507 case DB_EAST
: (*x
)++; break;
508 case DB_WEST
: (*x
)--; break;
513 * Creation of a drawbridge at pos x,y.
514 * dir is the direction.
515 * flag must be put to TRUE if we want the drawbridge to be opened.
519 create_drawbridge(x
,y
,dir
,flag
)
525 boolean lava
= levl
[x
][y
].typ
== LAVAPOOL
; /* assume initialized map */
542 impossible("bad direction in create_drawbridge");
549 if (!IS_WALL(levl
[x2
][y2
].typ
))
551 if (flag
) { /* We want the bridge open */
552 levl
[x
][y
].typ
= DRAWBRIDGE_DOWN
;
553 levl
[x2
][y2
].typ
= DOOR
;
554 levl
[x2
][y2
].doormask
= D_NODOOR
;
556 levl
[x
][y
].typ
= DRAWBRIDGE_UP
;
557 levl
[x2
][y2
].typ
= DBWALL
;
558 /* Drawbridges are non-diggable. */
559 levl
[x2
][y2
].wall_info
= W_NONDIGGABLE
;
561 levl
[x
][y
].horizontal
= !horiz
;
562 levl
[x2
][y2
].horizontal
= horiz
;
563 levl
[x
][y
].drawbridgemask
= dir
;
564 if(lava
) levl
[x
][y
].drawbridgemask
|= DB_LAVA
;
569 struct monst
*emon
; /* youmonst for the player */
570 struct permonst
*edata
; /* must be non-zero for record to be valid */
576 static NEARDATA
struct entity occupants
[ENTITIES
];
585 for (entitycnt
= 0; entitycnt
< ENTITIES
; entitycnt
++)
586 if ((occupants
[entitycnt
].edata
) &&
587 (occupants
[entitycnt
].ex
== x
) &&
588 (occupants
[entitycnt
].ey
== y
))
591 pline("entitycnt = %d", entitycnt
);
594 return((entitycnt
== ENTITIES
)?
595 (struct entity
*)0 : &(occupants
[entitycnt
]));
599 m_to_e(mtmp
, x
, y
, etmp
)
608 if (mtmp
->wormno
&& (x
!= mtmp
->mx
|| y
!= mtmp
->my
))
609 etmp
->edata
= &mons
[PM_LONG_WORM_TAIL
];
611 etmp
->edata
= mtmp
->data
;
613 etmp
->edata
= (struct permonst
*)0;
620 etmp
->emon
= &youmonst
;
623 etmp
->edata
= youmonst
.data
;
627 set_entity(x
, y
, etmp
)
631 if ((x
== u
.ux
) && (y
== u
.uy
))
633 else if (MON_AT(x
, y
))
634 m_to_e(m_at(x
, y
), x
, y
, etmp
);
636 etmp
->edata
= (struct permonst
*)0;
639 #define is_u(etmp) (etmp->emon == &youmonst)
640 #define e_canseemon(etmp) (is_u(etmp) ? (boolean)TRUE : canseemon(etmp->emon))
643 * e_strg is a utility routine which is not actually in use anywhere, since
644 * the specialized routines below suffice for all current purposes.
647 /* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */
649 STATIC_OVL
const char *
653 return(is_u(etmp
)? "you" : mon_nam(etmp
->emon
));
658 * Enam is another unused utility routine: E_phrase is preferable.
665 return(is_u(etmp
)? "You" : Monnam(etmp
->emon
));
670 * Generates capitalized entity name, makes 2nd -> 3rd person conversion on
671 * verb, where necessary.
674 STATIC_OVL
const char *
679 static char wholebuf
[80];
681 strcpy(wholebuf
, is_u(etmp
) ? "You" : Monnam(etmp
->emon
));
682 if (!*verb
) return(wholebuf
);
683 strcat(wholebuf
, " ");
685 strcat(wholebuf
, verb
);
687 strcat(wholebuf
, vtense((char *)0, verb
));
692 * Simple-minded "can it be here?" routine
696 e_survives_at(etmp
, x
, y
)
700 if (noncorporeal(etmp
->edata
))
703 return((boolean
)((is_u(etmp
) &&
704 (Wwalking
|| Race_if(PM_KORONST
) || Amphibious
|| Swimming
||
705 Flying
|| Levitation
)) ||
706 is_swimmer(etmp
->edata
) || is_flyer(etmp
->edata
) ||
707 is_floater(etmp
->edata
)));
708 /* must force call to lava_effects in e_died if is_u */
710 return (boolean
)((is_u(etmp
) && (Levitation
|| Flying
)) ||
711 likes_lava(etmp
->edata
) || is_flyer(etmp
->edata
));
712 if (is_db_wall(x
, y
))
713 return((boolean
)(is_u(etmp
) ? Passes_walls
:
714 passes_walls(etmp
->edata
)));
719 e_died(etmp
, dest
, how
)
724 if (how
== DROWNING
) {
725 killer
= 0; /* drown() sets its own killer */
727 } else if (how
== BURNING
) {
728 killer
= 0; /* lava_effects() sets its own killer */
729 (void) lava_effects();
730 } else if (uwep
&& uwep
->oartifact
== ART_BRIDGEBANE
) {
731 pline("Somehow, the drawbridge fails to kill you!");
732 } else if (uleft
&& uleft
->otyp
== RIN_IMMUNITY_TO_DRAWBRIDGES
) {
733 pline("Somehow, the drawbridge fails to kill you!");
734 } else if (uright
&& uright
->otyp
== RIN_IMMUNITY_TO_DRAWBRIDGES
) {
735 pline("Somehow, the drawbridge fails to kill you!");
740 /* use more specific killer if specified */
742 killer_format
= KILLED_BY_AN
;
743 killer
= "falling drawbridge";
747 /* So, you didn't die */
748 if (!e_survives_at(etmp
, etmp
->ex
, etmp
->ey
)) {
749 if (enexto(&xy
, etmp
->ex
, etmp
->ey
, etmp
->edata
)) {
750 pline("A %s force teleports you away...",
751 FunnyHallu
? "normal" : "strange");
752 teleds(xy
.x
, xy
.y
, FALSE
);
754 /* otherwise on top of the drawbridge is the
755 * only viable spot in the dungeon, so stay there
759 /* we might have crawled out of the moat to survive */
760 etmp
->ex
= u
.ux
, etmp
->ey
= u
.uy
;
765 /* fake "digested to death" damage-type suppresses corpse */
766 #define mk_message(dest) ((dest & 1) ? "" : (char *)0)
767 #define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS)
768 /* if monsters are moving, one of them caused the destruction */
769 if (flags
.mon_moving
)
770 monkilled(etmp
->emon
, mk_message(dest
), mk_corpse(dest
));
771 else /* you caused it */
772 xkilled(etmp
->emon
, dest
);
773 etmp
->edata
= (struct permonst
*)0;
775 /* dead long worm handling */
776 for (entitycnt
= 0; entitycnt
< ENTITIES
; entitycnt
++) {
777 if (etmp
!= &(occupants
[entitycnt
]) &&
778 etmp
->emon
== occupants
[entitycnt
].emon
)
779 occupants
[entitycnt
].edata
= (struct permonst
*)0;
788 * These are never directly affected by a bridge or portcullis.
795 return (boolean
)((is_u(etmp
) ? Passes_walls
:
796 passes_walls(etmp
->edata
)) || noncorporeal(etmp
->edata
));
800 * Does falling drawbridge or portcullis miss etmp?
804 e_missed(etmp
, chunks
)
812 pline("Do chunks miss?");
817 if (is_flyer(etmp
->edata
) &&
818 (is_u(etmp
)? !Sleeping
:
819 (etmp
->emon
->mcanmove
&& !etmp
->emon
->msleeping
)))
820 /* flying requires mobility */
821 misses
= 5; /* out of 8 */
822 else if (is_floater(etmp
->edata
) ||
823 (is_u(etmp
) && Levitation
)) /* doesn't require mobility */
825 else if (chunks
&& is_pool(etmp
->ex
, etmp
->ey
))
826 misses
= 2; /* sitting ducks */
830 if (is_db_wall(etmp
->ex
, etmp
->ey
))
831 misses
-= 3; /* less airspace */
834 pline("Miss chance = %d (out of 8)", misses
);
837 return((boolean
)((misses
>= rnd(8))? TRUE
: FALSE
));
841 * Can etmp jump from death?
848 int tmp
= 4; /* out of 10 */
850 if (is_u(etmp
)? (Sleeping
|| Fumbling
) :
851 (!etmp
->emon
->mcanmove
|| etmp
->emon
->msleeping
||
852 !etmp
->edata
->mmove
|| etmp
->emon
->wormno
))
855 if (is_u(etmp
)? Confusion
: etmp
->emon
->mconf
)
858 if (is_u(etmp
)? Stunned
: etmp
->emon
->mstun
)
861 if (is_db_wall(etmp
->ex
, etmp
->ey
))
862 tmp
-= 2; /* less room to maneuver */
865 pline("%s to jump (%d chances in 10)", E_phrase(etmp
, "try"), tmp
);
867 return((boolean
)((tmp
>= rnd(10))? TRUE
: FALSE
));
874 int newx
, newy
, at_portcullis
, oldx
, oldy
;
875 boolean must_jump
= FALSE
, relocates
= FALSE
, e_inview
;
881 e_inview
= e_canseemon(etmp
);
884 at_portcullis
= is_db_wall(oldx
, oldy
);
885 crm
= &levl
[oldx
][oldy
];
887 if (automiss(etmp
) && e_survives_at(etmp
, oldx
, oldy
)) {
888 if (e_inview
&& (at_portcullis
|| IS_DRAWBRIDGE(crm
->typ
)))
889 pline_The("%s passes through %s!",
890 at_portcullis
? "portcullis" : "drawbridge",
892 if (is_u(etmp
)) spoteffects(FALSE
);
895 if (e_missed(etmp
, FALSE
)) {
897 pline_The("portcullis misses %s!",
901 pline_The("drawbridge misses %s!",
904 if (e_survives_at(etmp
, oldx
, oldy
))
908 pline("Mon can't survive here");
913 relocates
= TRUE
; /* just ride drawbridge in */
916 if (crm
->typ
== DRAWBRIDGE_DOWN
) {
917 pline("%s crushed underneath the drawbridge.",
918 E_phrase(etmp
, "are")); /* no jump */
919 e_died(etmp
, e_inview
? 3 : 2, CRUSHING
);/* no corpse */
920 return; /* Note: Beyond this point, we know we're */
921 } /* not at an opened drawbridge, since all */
922 must_jump
= TRUE
; /* *missable* creatures survive on the */
923 } /* square, and all the unmissed ones die. */
929 pline("Jump succeeds!");
933 pline("%s crushed by the falling portcullis!",
934 E_phrase(etmp
, "are"));
935 else if (flags
.soundok
)
936 You_hear("a crushing sound.");
937 e_died(etmp
, e_inview
? 3 : 2, CRUSHING
);
941 } else { /* tries to jump off bridge to original square */
942 relocates
= !e_jumps(etmp
);
944 pline("Jump %s!", (relocates
)? "fails" : "succeeds");
950 * Here's where we try to do relocation. Assumes that etmp is not arriving
951 * at the portcullis square while the drawbridge is falling, since this square
952 * would be inaccessible (i.e. etmp started on drawbridge square) or
953 * unnecessary (i.e. etmp started here) in such a situation.
956 pline("Doing relocation.");
960 (void)find_drawbridge(&newx
, &newy
);
961 if ((newx
== oldx
) && (newy
== oldy
))
962 get_wall_for_db(&newx
, &newy
);
964 pline("Checking new square for occupancy.");
966 if (relocates
&& (e_at(newx
, newy
))) {
969 * Standoff problem: one or both entities must die, and/or both switch
970 * places. Avoid infinite recursion by checking first whether the other
971 * entity is staying put. Clean up if we happen to move/die in recursion.
973 struct entity
*other
;
975 other
= e_at(newx
, newy
);
977 pline("New square is occupied by %s", e_nam(other
));
979 if (e_survives_at(other
, newx
, newy
) && automiss(other
)) {
980 relocates
= FALSE
; /* "other" won't budge */
982 pline("%s suicide.", E_phrase(etmp
, "commit"));
987 pline("Handling %s", e_nam(other
));
989 while ((e_at(newx
, newy
) != 0) &&
990 (e_at(newx
, newy
) != etmp
))
993 pline("Checking existence of %s", e_nam(etmp
));
996 if (e_at(oldx
, oldy
) != etmp
) {
998 pline("%s moved or died in recursion somewhere",
999 E_phrase(etmp
, "have"));
1006 if (relocates
&& !e_at(newx
, newy
)) {/* if e_at() entity = worm tail */
1008 pline("Moving %s", e_nam(etmp
));
1011 remove_monster(etmp
->ex
, etmp
->ey
);
1012 place_monster(etmp
->emon
, newx
, newy
);
1013 update_monster_region(etmp
->emon
);
1020 e_inview
= e_canseemon(etmp
);
1023 pline("Final disposition of %s", e_nam(etmp
));
1026 if (is_db_wall(etmp
->ex
, etmp
->ey
)) {
1028 pline("%s in portcullis chamber", E_phrase(etmp
, "are"));
1033 You("tumble towards the closed portcullis!");
1035 You("pass through it!");
1037 pline_The("drawbridge closes in...");
1039 pline("%s behind the drawbridge.",
1040 E_phrase(etmp
, "disappear"));
1042 if (!e_survives_at(etmp
, etmp
->ex
, etmp
->ey
)) {
1043 killer_format
= KILLED_BY_AN
;
1044 killer
= "closing drawbridge";
1045 e_died(etmp
, 0, CRUSHING
); /* no message */
1049 pline("%s in here", E_phrase(etmp
, "survive"));
1053 pline("%s on drawbridge square", E_phrase(etmp
, "are"));
1055 if (is_pool(etmp
->ex
, etmp
->ey
) && !e_inview
)
1057 You_hear("a splash.");
1058 if (e_survives_at(etmp
, etmp
->ex
, etmp
->ey
)) {
1059 if (e_inview
&& !is_flyer(etmp
->edata
) &&
1060 !is_floater(etmp
->edata
))
1061 pline("%s from the bridge.",
1062 E_phrase(etmp
, "fall"));
1066 pline("%s cannot survive on the drawbridge square",Enam(etmp
));
1068 if (is_pool(etmp
->ex
, etmp
->ey
) || is_lava(etmp
->ex
, etmp
->ey
))
1069 if (e_inview
&& !is_u(etmp
)) {
1070 /* drown() will supply msgs if nec. */
1071 boolean lava
= is_lava(etmp
->ex
, etmp
->ey
);
1074 pline("%s the %s and disappears.",
1075 E_phrase(etmp
, "drink"),
1076 lava
? "lava" : "moat");
1078 pline("%s into the %s.",
1079 E_phrase(etmp
, "fall"),
1080 lava
? "lava" : "moat");
1082 killer_format
= NO_KILLER_PREFIX
;
1083 killer
= "fell from a drawbridge";
1084 e_died(etmp
, e_inview
? 3 : 2, /* CRUSHING is arbitrary */
1085 (is_pool(etmp
->ex
, etmp
->ey
)) ? DROWNING
:
1086 (is_lava(etmp
->ex
, etmp
->ey
)) ? BURNING
:
1087 CRUSHING
); /*no corpse*/
1093 * Close the drawbridge located at x,y
1097 close_drawbridge(x
,y
)
1100 register struct rm
*lev1
, *lev2
;
1105 if (lev1
->typ
!= DRAWBRIDGE_DOWN
) return;
1106 if (m_at(x
,y
) && bigmonst(m_at(x
,y
)->data
)) {
1107 pline("A monster blocks the drawbridge with its weight.");
1108 return; /* Sorry Patric, but I decided "big" monsters are supposed to big enough so they resist crushing. */
1111 pline("The mechanism seems to have something stuck in it and won't close.");
1112 return; /* And the odds of this happening may well be higher to further stop the player's exploits. --Amy */
1115 get_wall_for_db(&x2
,&y2
);
1116 if (cansee(x
,y
) || cansee(x2
,y2
))
1117 You("see a drawbridge %s up!",
1118 (((u
.ux
== x
|| u
.uy
== y
) && !Underwater
) ||
1119 distu(x2
,y2
) < distu(x
,y
)) ? "coming" : "going");
1120 lev1
->typ
= DRAWBRIDGE_UP
;
1121 lev2
= &levl
[x2
][y2
];
1123 switch (lev1
->drawbridgemask
& DB_DIR
) {
1126 lev2
->horizontal
= TRUE
;
1130 lev2
->horizontal
= FALSE
;
1133 lev2
->wall_info
= W_NONDIGGABLE
;
1134 set_entity(x
, y
, &(occupants
[0]));
1135 set_entity(x2
, y2
, &(occupants
[1]));
1136 do_entity(&(occupants
[0])); /* Do set_entity after first */
1137 set_entity(x2
, y2
, &(occupants
[1])); /* do_entity for worm tail */
1138 do_entity(&(occupants
[1]));
1139 if(OBJ_AT(x
,y
) && flags
.soundok
)
1140 You_hear("smashing and crushing.");
1141 (void) revive_nasty(x
,y
,(char *)0);
1142 (void) revive_nasty(x2
,y2
,(char *)0);
1145 if ((t
= t_at(x
, y
)) != 0) deltrap(t
);
1146 if ((t
= t_at(x2
, y2
)) != 0) deltrap(t
);
1149 block_point(x2
,y2
); /* vision */
1153 * Open the drawbridge located at x,y
1157 open_drawbridge(x
,y
)
1160 register struct rm
*lev1
, *lev2
;
1165 if (lev1
->typ
!= DRAWBRIDGE_UP
) return;
1167 get_wall_for_db(&x2
,&y2
);
1168 if (cansee(x
,y
) || cansee(x2
,y2
))
1169 You("see a drawbridge %s down!",
1170 (distu(x2
,y2
) < distu(x
,y
)) ? "going" : "coming");
1171 lev1
->typ
= DRAWBRIDGE_DOWN
;
1172 lev2
= &levl
[x2
][y2
];
1174 lev2
->doormask
= D_NODOOR
;
1175 set_entity(x
, y
, &(occupants
[0]));
1176 set_entity(x2
, y2
, &(occupants
[1]));
1177 do_entity(&(occupants
[0])); /* do set_entity after first */
1178 set_entity(x2
, y2
, &(occupants
[1])); /* do_entity for worm tails */
1179 do_entity(&(occupants
[1]));
1180 (void) revive_nasty(x
,y
,(char *)0);
1182 if ((t
= t_at(x
, y
)) != 0) deltrap(t
);
1183 if ((t
= t_at(x2
, y2
)) != 0) deltrap(t
);
1186 unblock_point(x2
,y2
); /* vision */
1187 if (Is_stronghold(&u
.uz
)) u
.uevent
.uopened_dbridge
= TRUE
;
1191 * Let's destroy the drawbridge located at x,y
1195 destroy_drawbridge(x
,y
)
1198 register struct rm
*lev1
, *lev2
;
1202 struct entity
*etmp1
= &(occupants
[0]), *etmp2
= &(occupants
[1]);
1205 if (!IS_DRAWBRIDGE(lev1
->typ
))
1208 get_wall_for_db(&x2
,&y2
);
1209 lev2
= &levl
[x2
][y2
];
1210 if ((lev1
->drawbridgemask
& DB_UNDER
) == DB_MOAT
||
1211 (lev1
->drawbridgemask
& DB_UNDER
) == DB_LAVA
) {
1213 boolean lava
= (lev1
->drawbridgemask
& DB_UNDER
) == DB_LAVA
;
1214 if (lev1
->typ
== DRAWBRIDGE_UP
) {
1216 pline_The("portcullis of the drawbridge falls into the %s!",
1217 lava
? "lava" : "moat");
1218 else if (flags
.soundok
)
1219 You_hear("a loud *SPLASH*!");
1222 pline_The("drawbridge collapses into the %s!",
1223 lava
? "lava" : "moat");
1224 else if (flags
.soundok
)
1225 You_hear("a loud *SPLASH*!");
1227 lev1
->typ
= lava
? LAVAPOOL
: MOAT
;
1228 lev1
->drawbridgemask
= 0;
1229 if ((otmp
= sobj_at(BOULDER
,x
,y
)) != 0) {
1230 obj_extract_self(otmp
);
1231 (void) flooreffects(otmp
,x
,y
,"fall");
1235 pline_The("drawbridge disintegrates!");
1237 You_hear("a loud *CRASH*!");
1239 ((lev1
->drawbridgemask
& DB_ICE
) ? ICE
: ROOM
);
1241 ((lev1
->drawbridgemask
& DB_ICE
) ? ICED_MOAT
: 0);
1243 wake_nearto(x
, y
, 500);
1245 lev2
->doormask
= D_NODOOR
;
1246 if ((t
= t_at(x
, y
)) != 0) deltrap(t
);
1247 if ((t
= t_at(x2
, y2
)) != 0) deltrap(t
);
1250 if (!does_block(x2
,y2
,lev2
)) unblock_point(x2
,y2
); /* vision */
1251 if (Is_stronghold(&u
.uz
)) u
.uevent
.uopened_dbridge
= TRUE
;
1253 set_entity(x2
, y2
, etmp2
); /* currently only automissers can be here */
1255 e_inview
= e_canseemon(etmp2
);
1256 if (!automiss(etmp2
)) {
1258 pline("%s blown apart by flying debris.",
1259 E_phrase(etmp2
, "are"));
1260 killer_format
= KILLED_BY_AN
;
1261 killer
= "exploding drawbridge";
1262 e_died(etmp2
, e_inview
? 3 : 2, CRUSHING
); /*no corpse*/
1263 } /* nothing which is vulnerable can survive this */
1265 set_entity(x
, y
, etmp1
);
1267 e_inview
= e_canseemon(etmp1
);
1268 if (e_missed(etmp1
, TRUE
)) {
1270 pline("%s spared!", E_phrase(etmp1
, "are"));
1274 if (!is_u(etmp1
) && FunnyHallu
)
1275 pline("%s into some heavy metal!",
1276 E_phrase(etmp1
, "get"));
1278 pline("%s hit by a huge chunk of metal!",
1279 E_phrase(etmp1
, "are"));
1281 if (flags
.soundok
&& !is_u(etmp1
) && !is_pool(x
,y
))
1282 You_hear("a crushing sound.");
1285 pline("%s from shrapnel",
1286 E_phrase(etmp1
, "die"));
1289 killer_format
= KILLED_BY_AN
;
1290 killer
= "collapsing drawbridge";
1291 e_died(etmp1
, e_inview
? 3 : 2, CRUSHING
); /*no corpse*/
1292 if(lev1
->typ
== MOAT
) do_entity(etmp1
);