1 | /* SCCS Id: @(#)dbridge.c 3.3 2000/02/05 */
2 | /* Copyright (c) 1989 by Jean-Christophe Collet */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | /*
6 | * This file contains the drawbridge manipulation (create, open, close,
7 | * destroy).
8 | *
9 | * Added comprehensive monster-handling, and the "entity" structure to
10 | * deal with players as well. - 11/89
11 | */
12 |
13 | #include "hack.h"
14 |
15 | #ifdef OVLB
16 | STATIC_DCL void FDECL(get_wall_for_db, (int *, int *));
17 | STATIC_DCL struct entity *FDECL(e_at, (int, int));
18 | STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *));
19 | STATIC_DCL void FDECL(u_to_e, (struct entity *));
20 | STATIC_DCL void FDECL(set_entity, (int, int, struct entity *));
21 | STATIC_DCL const char *FDECL(e_nam, (struct entity *));
22 | #ifdef D_DEBUG
23 | static const char *FDECL(Enam, (struct entity *)); /* unused */
24 | #endif
25 | STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *));
26 | STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int));
27 | STATIC_DCL void FDECL(e_died, (struct entity *, int, int));
28 | STATIC_DCL boolean FDECL(automiss, (struct entity *));
29 | STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P));
30 | STATIC_DCL boolean FDECL(e_jumps, (struct entity *));
31 | STATIC_DCL void FDECL(do_entity, (struct entity *));
32 | #endif /* OVLB */
33 |
34 | #ifdef OVL0
35 |
36 | boolean
37 | is_pool(x,y)
38 | int x,y;
39 | {
40 | schar ltyp;
41 |
42 | if (!isok(x,y)) return FALSE;
43 | ltyp = levl[x][y].typ;
44 | if (ltyp == POOL || ltyp == MOAT || ltyp == WATER) return TRUE;
45 | if (ltyp == DRAWBRIDGE_UP &&
46 | (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT) return TRUE;
47 | return FALSE;
48 | }
49 |
50 | boolean
51 | is_lava(x,y)
52 | int x,y;
53 | {
54 | schar ltyp;
55 |
56 | if (!isok(x,y)) return FALSE;
57 | ltyp = levl[x][y].typ;
58 | if (ltyp == LAVAPOOL
59 | || (ltyp == DRAWBRIDGE_UP
60 | && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA)) return TRUE;
61 | return FALSE;
62 | }
63 |
64 | boolean
65 | is_ice(x,y)
66 | int x,y;
67 | {
68 | schar ltyp;
69 |
70 | if (!isok(x,y)) return FALSE;
71 | ltyp = levl[x][y].typ;
72 | if (ltyp == ICE
73 | || (ltyp == DRAWBRIDGE_UP
74 | && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) return TRUE;
75 | return FALSE;
76 | }
77 |
78 | #endif /* OVL0 */
79 |
80 | #ifdef OVL1
81 |
82 | /*
83 | * We want to know whether a wall (or a door) is the portcullis (passageway)
84 | * of an eventual drawbridge.
85 | *
86 | * Return value: the direction of the drawbridge.
87 | */
88 |
89 | int
90 | is_drawbridge_wall(x,y)
91 | int x,y;
92 | {
93 | struct rm *lev;
94 |
95 | lev = &levl[x][y];
96 | if (lev->typ != DOOR && lev->typ != DBWALL)
97 | return (-1);
98 |
99 | if (IS_DRAWBRIDGE(levl[x+1][y].typ) &&
100 | (levl[x+1][y].drawbridgemask & DB_DIR) == DB_WEST)
101 | return (DB_WEST);
102 | if (IS_DRAWBRIDGE(levl[x-1][y].typ) &&
103 | (levl[x-1][y].drawbridgemask & DB_DIR) == DB_EAST)
104 | return (DB_EAST);
105 | if (IS_DRAWBRIDGE(levl[x][y-1].typ) &&
106 | (levl[x][y-1].drawbridgemask & DB_DIR) == DB_SOUTH)
107 | return (DB_SOUTH);
108 | if (IS_DRAWBRIDGE(levl[x][y+1].typ) &&
109 | (levl[x][y+1].drawbridgemask & DB_DIR) == DB_NORTH)
110 | return (DB_NORTH);
111 |
112 | return (-1);
113 | }
114 |
115 | /*
116 | * Use is_db_wall where you want to verify that a
117 | * drawbridge "wall" is UP in the location x, y
118 | * (instead of UP or DOWN, as with is_drawbridge_wall).
119 | */
120 | boolean
121 | is_db_wall(x,y)
122 | int x,y;
123 | {
124 | return((boolean)( levl[x][y].typ == DBWALL ));
125 | }
126 |
127 |
128 | /*
129 | * Return true with x,y pointing to the drawbridge if x,y initially indicate
130 | * a drawbridge or drawbridge wall.
131 | */
132 | boolean
133 | find_drawbridge(x,y)
134 | int *x,*y;
135 | {
136 | int dir;
137 |
138 | if (IS_DRAWBRIDGE(levl[*x][*y].typ))
139 | return TRUE;
140 | dir = is_drawbridge_wall(*x,*y);
141 | if (dir >= 0) {
142 | switch(dir) {
143 | case DB_NORTH: (*y)++; break;
144 | case DB_SOUTH: (*y)--; break;
145 | case DB_EAST: (*x)--; break;
146 | case DB_WEST: (*x)++; break;
147 | }
148 | return TRUE;
149 | }
150 | return FALSE;
151 | }
152 |
153 | #endif /* OVL1 */
154 | #ifdef OVLB
155 |
156 | /*
157 | * Find the drawbridge wall associated with a drawbridge.
158 | */
159 | STATIC_OVL void
160 | get_wall_for_db(x,y)
161 | int *x,*y;
162 | {
163 | switch (levl[*x][*y].drawbridgemask & DB_DIR) {
164 | case DB_NORTH: (*y)--; break;
165 | case DB_SOUTH: (*y)++; break;
166 | case DB_EAST: (*x)++; break;
167 | case DB_WEST: (*x)--; break;
168 | }
169 | }
170 |
171 | /*
172 | * Creation of a drawbridge at pos x,y.
173 | * dir is the direction.
174 | * flag must be put to TRUE if we want the drawbridge to be opened.
175 | */
176 |
177 | boolean
178 | create_drawbridge(x,y,dir,flag)
179 | int x,y,dir;
180 | boolean flag;
181 | {
182 | int x2,y2;
183 | boolean horiz;
184 | boolean lava = levl[x][y].typ == LAVAPOOL; /* assume initialized map */
185 |
186 | x2 = x; y2 = y;
187 | switch(dir) {
188 | case DB_NORTH:
189 | horiz = TRUE;
190 | y2--;
191 | break;
192 | case DB_SOUTH:
193 | horiz = TRUE;
194 | y2++;
195 | break;
196 | case DB_EAST:
197 | horiz = FALSE;
198 | x2++;
199 | break;
200 | default:
201 | impossible("bad direction in create_drawbridge");
202 | /* fall through */
203 | case DB_WEST:
204 | horiz = FALSE;
205 | x2--;
206 | break;
207 | }
208 | if (!IS_WALL(levl[x2][y2].typ))
209 | return(FALSE);
210 | if (flag) { /* We want the bridge open */
211 | levl[x][y].typ = DRAWBRIDGE_DOWN;
212 | levl[x2][y2].typ = DOOR;
213 | levl[x2][y2].doormask = D_NODOOR;
214 | } else {
215 | levl[x][y].typ = DRAWBRIDGE_UP;
216 | levl[x2][y2].typ = DBWALL;
217 | /* Drawbridges are non-diggable. */
218 | levl[x2][y2].wall_info = W_NONDIGGABLE;
219 | }
220 | levl[x][y].horizontal = !horiz;
221 | levl[x2][y2].horizontal = horiz;
222 | levl[x][y].drawbridgemask = dir;
223 | if(lava) levl[x][y].drawbridgemask |= DB_LAVA;
224 | return(TRUE);
225 | }
226 |
227 | struct entity {
228 | struct monst *emon; /* youmonst for the player */
229 | struct permonst *edata; /* must be non-zero for record to be valid */
230 | int ex, ey;
231 | };
232 |
233 | #define ENTITIES 2
234 |
235 | static NEARDATA struct entity occupants[ENTITIES];
236 |
237 | STATIC_OVL
238 | struct entity *
239 | e_at(x, y)
240 | int x, y;
241 | {
242 | int entitycnt;
243 |
244 | for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++)
245 | if ((occupants[entitycnt].edata) &&
246 | (occupants[entitycnt].ex == x) &&
247 | (occupants[entitycnt].ey == y))
248 | break;
249 | #ifdef D_DEBUG
250 | pline("entitycnt = %d", entitycnt);
251 | wait_synch();
252 | #endif
253 | return((entitycnt == ENTITIES)?
254 | (struct entity *)0 : &(occupants[entitycnt]));
255 | }
256 |
257 | STATIC_OVL void
258 | m_to_e(mtmp, x, y, etmp)
259 | struct monst *mtmp;
260 | int x, y;
261 | struct entity *etmp;
262 | {
263 | etmp->emon = mtmp;
264 | if (mtmp) {
265 | etmp->ex = x;
266 | etmp->ey = y;
267 | if (mtmp->wormno && (x != mtmp->mx || y != mtmp->my))
268 | etmp->edata = &mons[PM_LONG_WORM_TAIL];
269 | else
270 | etmp->edata = mtmp->data;
271 | } else
272 | etmp->edata = (struct permonst *)0;
273 | }
274 |
275 | STATIC_OVL void
276 | u_to_e(etmp)
277 | struct entity *etmp;
278 | {
279 | etmp->emon = &youmonst;
280 | etmp->ex = u.ux;
281 | etmp->ey = u.uy;
282 | etmp->edata = youmonst.data;
283 | }
284 |
285 | STATIC_OVL void
286 | set_entity(x, y, etmp)
287 | int x, y;
288 | struct entity *etmp;
289 | {
290 | if ((x == u.ux) && (y == u.uy))
291 | u_to_e(etmp);
292 | else if (MON_AT(x, y))
293 | m_to_e(m_at(x, y), x, y, etmp);
294 | else
295 | etmp->edata = (struct permonst *)0;
296 | }
297 |
298 | #define is_u(etmp) (etmp->emon == &youmonst)
299 | #define e_canseemon(etmp) (is_u(etmp) ? (boolean)TRUE : canseemon(etmp->emon))
300 |
301 | /*
302 | * e_strg is a utility routine which is not actually in use anywhere, since
303 | * the specialized routines below suffice for all current purposes.
304 | */
305 |
306 | /* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */
307 |
308 | STATIC_OVL const char *
309 | e_nam(etmp)
310 | struct entity *etmp;
311 | {
312 | return(is_u(etmp)? "you" : mon_nam(etmp->emon));
313 | }
314 |
315 | #ifdef D_DEBUG
316 | /*
317 | * Enam is another unused utility routine: E_phrase is preferable.
318 | */
319 |
320 | static const char *
321 | Enam(etmp)
322 | struct entity *etmp;
323 | {
324 | return(is_u(etmp)? "You" : Monnam(etmp->emon));
325 | }
326 | #endif /* D_DEBUG */
327 |
328 | /*
329 | * Generates capitalized entity name, makes 2nd -> 3rd person conversion on
330 | * verb, where necessary.
331 | */
332 |
333 | STATIC_OVL const char *
334 | E_phrase(etmp, verb)
335 | struct entity *etmp;
336 | const char *verb;
337 | {
338 | static char wholebuf[80];
339 | char verbbuf[30];
340 |
341 | Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon));
342 | if (!*verb)
343 | return(wholebuf);
344 | Strcat(wholebuf, " ");
345 | verbbuf[0] = '\0';
346 | if (is_u(etmp))
347 | Strcpy(verbbuf, verb);
348 | else {
349 | if (!strcmp(verb, "are"))
350 | Strcpy(verbbuf, "is");
351 | if (!strcmp(verb, "have"))
352 | Strcpy(verbbuf, "has");
353 | if (!verbbuf[0]) {
354 | Strcpy(verbbuf, verb);
355 | switch (verbbuf[strlen(verbbuf) - 1]) {
356 | case 'y':
357 | verbbuf[strlen(verbbuf) - 1] = '\0';
358 | Strcat(verbbuf, "ies");
359 | break;
360 | case 'h':
361 | case 'o':
362 | case 's':
363 | Strcat(verbbuf, "es");
364 | break;
365 | default:
366 | Strcat(verbbuf, "s");
367 | break;
368 | }
369 | }
370 | }
371 | Strcat(wholebuf, verbbuf);
372 | return(wholebuf);
373 | }
374 |
375 | /*
376 | * Simple-minded "can it be here?" routine
377 | */
378 |
379 | STATIC_OVL boolean
380 | e_survives_at(etmp, x, y)
381 | struct entity *etmp;
382 | int x, y;
383 | {
384 | if (noncorporeal(etmp->edata))
385 | return(TRUE);
386 | if (is_pool(x, y))
387 | return (boolean)((is_u(etmp) &&
388 | (Wwalking || Amphibious || Swimming ||
389 | Flying || Levitation)) ||
390 | is_swimmer(etmp->edata) || is_flyer(etmp->edata) ||
391 | is_floater(etmp->edata));
392 | /* must force call to lava_effects in e_died if is_u */
393 | if (is_lava(x, y))
394 | return (boolean)((is_u(etmp) && (Levitation || Flying)) ||
395 | likes_lava(etmp->edata) || is_flyer(etmp->edata));
396 | if (is_db_wall(x, y))
397 | return((boolean)(is_u(etmp) ? Passes_walls :
398 | passes_walls(etmp->edata)));
399 | return(TRUE);
400 | }
401 |
402 | STATIC_OVL void
403 | e_died(etmp, dest, how)
404 | struct entity *etmp;
405 | int dest, how;
406 | {
407 | if (is_u(etmp)) {
408 | if (how == DROWNING) {
409 | killer = 0; /* drown() sets its own killer */
410 | (void) drown();
411 | } else if (how == BURNING) {
412 | killer = 0; /* lava_effects() sets its own killer */
413 | (void) lava_effects();
414 | } else {
415 | coord xy;
416 |
417 | /* use more specific killer if specified */
418 | if (!killer) {
419 | killer_format = KILLED_BY_AN;
420 | killer = "falling drawbridge";
421 | }
422 | done(how);
423 | /* So, you didn't die */
424 | if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
425 | if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
426 | pline("A %s force teleports you away...",
427 | Hallucination ? "normal" : "strange");
428 | teleds(xy.x, xy.y);
429 | }
430 | /* otherwise on top of the drawbridge is the
431 | * only viable spot in the dungeon, so stay there
432 | */
433 | }
434 | }
435 | /* we might have crawled out of the moat to survive */
436 | etmp->ex = u.ux, etmp->ey = u.uy;
437 | } else {
438 | killer = 0;
439 | /* fake "digested to death" damage-type suppresses corpse */
440 | #define mk_message(dest) ((dest & 1) ? "" : (char *)0)
441 | #define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS)
442 | /* if monsters are moving, one of them caused the destruction */
443 | if (flags.mon_moving)
444 | monkilled(etmp->emon, mk_message(dest), mk_corpse(dest));
445 | else /* you caused it */
446 | xkilled(etmp->emon, dest);
447 | etmp->edata = (struct permonst *)0;
448 | #undef mk_message
449 | #undef mk_corpse
450 | }
451 | }
452 |
453 |
454 | /*
455 | * These are never directly affected by a bridge or portcullis.
456 | */
457 |
458 | STATIC_OVL boolean
459 | automiss(etmp)
460 | struct entity *etmp;
461 | {
462 | return (boolean)((is_u(etmp) ? Passes_walls :
463 | passes_walls(etmp->edata)) || noncorporeal(etmp->edata));
464 | }
465 |
466 | /*
467 | * Does falling drawbridge or portcullis miss etmp?
468 | */
469 |
470 | STATIC_OVL boolean
471 | e_missed(etmp, chunks)
472 | struct entity *etmp;
473 | boolean chunks;
474 | {
475 | int misses;
476 |
477 | #ifdef D_DEBUG
478 | if (chunks)
479 | pline("Do chunks miss?");
480 | #endif
481 | if (automiss(etmp))
482 | return(TRUE);
483 |
484 | if (is_flyer(etmp->edata) &&
485 | (is_u(etmp)? !Sleeping :
486 | (etmp->emon->mcanmove && !etmp->emon->msleeping)))
487 | /* flying requires mobility */
488 | misses = 5; /* out of 8 */
489 | else if (is_floater(etmp->edata) ||
490 | (is_u(etmp) && Levitation)) /* doesn't require mobility */
491 | misses = 3;
492 | else if (chunks && is_pool(etmp->ex, etmp->ey))
493 | misses = 2; /* sitting ducks */
494 | else
495 | misses = 0;
496 |
497 | if (is_db_wall(etmp->ex, etmp->ey))
498 | misses -= 3; /* less airspace */
499 |
500 | #ifdef D_DEBUG
501 | pline("Miss chance = %d (out of 8)", misses);
502 | #endif
503 |
504 | return((boolean)((misses >= rnd(8))? TRUE : FALSE));
505 | }
506 |
507 | /*
508 | * Can etmp jump from death?
509 | */
510 |
511 | STATIC_OVL boolean
512 | e_jumps(etmp)
513 | struct entity *etmp;
514 | {
515 | int tmp = 4; /* out of 10 */
516 |
517 | if (is_u(etmp)? (Sleeping || Fumbling) :
518 | (!etmp->emon->mcanmove || etmp->emon->msleeping ||
519 | !etmp->edata->mmove || etmp->emon->wormno))
520 | return(FALSE);
521 |
522 | if (is_u(etmp)? Confusion : etmp->emon->mconf)
523 | tmp -= 2;
524 |
525 | if (is_u(etmp)? Stunned : etmp->emon->mstun)
526 | tmp -= 3;
527 |
528 | if (is_db_wall(etmp->ex, etmp->ey))
529 | tmp -= 2; /* less room to maneuver */
530 |
531 | #ifdef D_DEBUG
532 | pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp);
533 | #endif
534 | return((boolean)((tmp >= rnd(10))? TRUE : FALSE));
535 | }
536 |
537 | STATIC_OVL void
538 | do_entity(etmp)
539 | struct entity *etmp;
540 | {
541 | int newx, newy, at_portcullis, oldx, oldy;
542 | boolean must_jump = FALSE, relocates = FALSE, e_inview;
543 | struct rm *crm;
544 |
545 | if (!etmp->edata)
546 | return;
547 |
548 | e_inview = e_canseemon(etmp);
549 | oldx = etmp->ex;
550 | oldy = etmp->ey;
551 | at_portcullis = is_db_wall(oldx, oldy);
552 | crm = &levl[oldx][oldy];
553 |
554 | if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
555 | if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
556 | pline_The("%s passes through %s!",
557 | at_portcullis ? "portcullis" : "drawbridge",
558 | e_nam(etmp));
559 | return;
560 | }
561 | if (e_missed(etmp, FALSE)) {
562 | if (at_portcullis)
563 | pline_The("portcullis misses %s!",
564 | e_nam(etmp));
565 | #ifdef D_DEBUG
566 | else
567 | pline_The("drawbridge misses %s!",
568 | e_nam(etmp));
569 | #endif
570 | if (e_survives_at(etmp, oldx, oldy))
571 | return;
572 | else {
573 | #ifdef D_DEBUG
574 | pline("Mon can't survive here");
575 | #endif
576 | if (at_portcullis)
577 | must_jump = TRUE;
578 | else
579 | relocates = TRUE; /* just ride drawbridge in */
580 | }
581 | } else {
582 | if (crm->typ == DRAWBRIDGE_DOWN) {
583 | pline("%s crushed underneath the drawbridge.",
584 | E_phrase(etmp, "are")); /* no jump */
585 | e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */
586 | return; /* Note: Beyond this point, we know we're */
587 | } /* not at an opened drawbridge, since all */
588 | must_jump = TRUE; /* *missable* creatures survive on the */
589 | } /* square, and all the unmissed ones die. */
590 | if (must_jump) {
591 | if (at_portcullis) {
592 | if (e_jumps(etmp)) {
593 | relocates = TRUE;
594 | #ifdef D_DEBUG
595 | pline("Jump succeeds!");
596 | #endif
597 | } else {
598 | if (e_inview)
599 | pline("%s crushed by the falling portcullis!",
600 | E_phrase(etmp, "are"));
601 | else if (flags.soundok)
602 | You_hear("a crushing sound.");
603 | e_died(etmp, e_inview? 3 : 2, CRUSHING);
604 | /* no corpse */
605 | return;
606 | }
607 | } else { /* tries to jump off bridge to original square */
608 | relocates = !e_jumps(etmp);
609 | #ifdef D_DEBUG
610 | pline("Jump %s!", (relocates)? "fails" : "succeeds");
611 | #endif
612 | }
613 | }
614 |
615 | /*
616 | * Here's where we try to do relocation. Assumes that etmp is not arriving
617 | * at the portcullis square while the drawbridge is falling, since this square
618 | * would be inaccessible (i.e. etmp started on drawbridge square) or
619 | * unnecessary (i.e. etmp started here) in such a situation.
620 | */
621 | #ifdef D_DEBUG
622 | pline("Doing relocation.");
623 | #endif
624 | newx = oldx;
625 | newy = oldy;
626 | (void)find_drawbridge(&newx, &newy);
627 | if ((newx == oldx) && (newy == oldy))
628 | get_wall_for_db(&newx, &newy);
629 | #ifdef D_DEBUG
630 | pline("Checking new square for occupancy.");
631 | #endif
632 | if (relocates && (e_at(newx, newy))) {
633 |
634 | /*
635 | * Standoff problem: one or both entities must die, and/or both switch
636 | * places. Avoid infinite recursion by checking first whether the other
637 | * entity is staying put. Clean up if we happen to move/die in recursion.
638 | */
639 | struct entity *other;
640 |
641 | other = e_at(newx, newy);
642 | #ifdef D_DEBUG
643 | pline("New square is occupied by %s", e_nam(other));
644 | #endif
645 | if (e_survives_at(other, newx, newy) && automiss(other)) {
646 | relocates = FALSE; /* "other" won't budge */
647 | #ifdef D_DEBUG
648 | pline("%s suicide.", E_phrase(etmp, "commit"));
649 | #endif
650 | } else {
651 |
652 | #ifdef D_DEBUG
653 | pline("Handling %s", e_nam(other));
654 | #endif
655 | while ((e_at(newx, newy) != 0) &&
656 | (e_at(newx, newy) != etmp))
657 | do_entity(other);
658 | #ifdef D_DEBUG
659 | pline("Checking existence of %s", e_nam(etmp));
660 | wait_synch();
661 | #endif
662 | if (e_at(oldx, oldy) != etmp) {
663 | #ifdef D_DEBUG
664 | pline("%s moved or died in recursion somewhere",
665 | E_phrase(etmp, "have"));
666 | wait_synch();
667 | #endif
668 | return;
669 | }
670 | }
671 | }
672 | if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */
673 | #ifdef D_DEBUG
674 | pline("Moving %s", e_nam(etmp));
675 | #endif
676 | if (!is_u(etmp)) {
677 | remove_monster(etmp->ex, etmp->ey);
678 | place_monster(etmp->emon, newx, newy);
679 | update_monster_region(etmp->emon);
680 | } else {
681 | u.ux = newx;
682 | u.uy = newy;
683 | }
684 | etmp->ex = newx;
685 | etmp->ey = newy;
686 | e_inview = e_canseemon(etmp);
687 | }
688 | #ifdef D_DEBUG
689 | pline("Final disposition of %s", e_nam(etmp));
690 | wait_synch();
691 | #endif
692 | if (is_db_wall(etmp->ex, etmp->ey)) {
693 | #ifdef D_DEBUG
694 | pline("%s in portcullis chamber", E_phrase(etmp, "are"));
695 | wait_synch();
696 | #endif
697 | if (e_inview) {
698 | if (is_u(etmp)) {
699 | You("tumble towards the closed portcullis!");
700 | if (automiss(etmp))
701 | You("pass through it!");
702 | else
703 | pline_The("drawbridge closes in...");
704 | } else
705 | pline("%s behind the drawbridge.",
706 | E_phrase(etmp, "disappear"));
707 | }
708 | if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
709 | killer_format = KILLED_BY_AN;
710 | killer = "closing drawbridge";
711 | e_died(etmp, 0, CRUSHING); /* no message */
712 | return;
713 | }
714 | #ifdef D_DEBUG
715 | pline("%s in here", E_phrase(etmp, "survive"));
716 | #endif
717 | } else {
718 | #ifdef D_DEBUG
719 | pline("%s on drawbridge square", E_phrase(etmp, "are"));
720 | #endif
721 | if (is_pool(etmp->ex, etmp->ey) && !e_inview)
722 | if (flags.soundok)
723 | You_hear("a splash.");
724 | if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
725 | if (e_inview && !is_flyer(etmp->edata) &&
726 | !is_floater(etmp->edata))
727 | pline("%s from the bridge.",
728 | E_phrase(etmp, "fall"));
729 | return;
730 | }
731 | #ifdef D_DEBUG
732 | pline("%s cannot survive on the drawbridge square",Enam(etmp));
733 | #endif
734 | if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey))
735 | if (e_inview && !is_u(etmp)) {
736 | /* drown() will supply msgs if nec. */
737 | boolean lava = is_lava(etmp->ex, etmp->ey);
738 |
739 | if (Hallucination)
740 | pline("%s the %s and disappears.",
741 | E_phrase(etmp, "drink"),
742 | lava ? "lava" : "moat");
743 | else
744 | pline("%s into the %s.",
745 | E_phrase(etmp, "fall"),
746 | lava ? "lava" : "moat");
747 | }
748 | killer_format = NO_KILLER_PREFIX;
749 | killer = "fell from a drawbridge";
750 | e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */
751 | (is_pool(etmp->ex, etmp->ey)) ? DROWNING :
752 | (is_lava(etmp->ex, etmp->ey)) ? BURNING :
753 | CRUSHING); /*no corpse*/
754 | return;
755 | }
756 | }
757 |
758 | /*
759 | * Close the drawbridge located at x,y
760 | */
761 |
762 | void
763 | close_drawbridge(x,y)
764 | int x,y;
765 | {
766 | register struct rm *lev1, *lev2;
767 | struct trap *t;
768 | int x2, y2;
769 |
770 | lev1 = &levl[x][y];
771 | if (lev1->typ != DRAWBRIDGE_DOWN) return;
772 | x2 = x; y2 = y;
773 | get_wall_for_db(&x2,&y2);
774 | if (cansee(x,y) || cansee(x2,y2))
775 | You("see a drawbridge %s up!",
776 | (((u.ux == x || u.uy == y) && !Underwater) ||
777 | distu(x2,y2) < distu(x,y)) ? "coming" : "going");
778 | lev1->typ = DRAWBRIDGE_UP;
779 | lev2 = &levl[x2][y2];
780 | lev2->typ = DBWALL;
781 | switch (lev1->drawbridgemask & DB_DIR) {
782 | case DB_NORTH:
783 | case DB_SOUTH:
784 | lev2->horizontal = TRUE;
785 | break;
786 | case DB_WEST:
787 | case DB_EAST:
788 | lev2->horizontal = FALSE;
789 | break;
790 | }
791 | lev2->wall_info = W_NONDIGGABLE;
792 | set_entity(x, y, &(occupants[0]));
793 | set_entity(x2, y2, &(occupants[1]));
794 | do_entity(&(occupants[0])); /* Do set_entity after first */
795 | set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */
796 | do_entity(&(occupants[1]));
797 | if(OBJ_AT(x,y) && flags.soundok)
798 | You_hear("smashing and crushing.");
799 | (void) revive_nasty(x,y,(char *)0);
800 | (void) revive_nasty(x2,y2,(char *)0);
801 | delallobj(x, y);
802 | delallobj(x2, y2);
803 | if ((t = t_at(x, y)) != 0) deltrap(t);
804 | if ((t = t_at(x2, y2)) != 0) deltrap(t);
805 | newsym(x, y);
806 | newsym(x2, y2);
807 | block_point(x2,y2); /* vision */
808 | }
809 |
810 | /*
811 | * Open the drawbridge located at x,y
812 | */
813 |
814 | void
815 | open_drawbridge(x,y)
816 | int x,y;
817 | {
818 | register struct rm *lev1, *lev2;
819 | struct trap *t;
820 | int x2, y2;
821 |
822 | lev1 = &levl[x][y];
823 | if (lev1->typ != DRAWBRIDGE_UP) return;
824 | x2 = x; y2 = y;
825 | get_wall_for_db(&x2,&y2);
826 | if (cansee(x,y) || cansee(x2,y2))
827 | You("see a drawbridge %s down!",
828 | (distu(x2,y2) < distu(x,y)) ? "going" : "coming");
829 | lev1->typ = DRAWBRIDGE_DOWN;
830 | lev2 = &levl[x2][y2];
831 | lev2->typ = DOOR;
832 | lev2->doormask = D_NODOOR;
833 | set_entity(x, y, &(occupants[0]));
834 | set_entity(x2, y2, &(occupants[1]));
835 | do_entity(&(occupants[0])); /* do set_entity after first */
836 | set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */
837 | do_entity(&(occupants[1]));
838 | (void) revive_nasty(x,y,(char *)0);
839 | delallobj(x, y);
840 | if ((t = t_at(x, y)) != 0) deltrap(t);
841 | if ((t = t_at(x2, y2)) != 0) deltrap(t);
842 | newsym(x, y);
843 | newsym(x2, y2);
844 | unblock_point(x2,y2); /* vision */
845 | if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
846 | }
847 |
848 | /*
849 | * Let's destroy the drawbridge located at x,y
850 | */
851 |
852 | void
853 | destroy_drawbridge(x,y)
854 | int x,y;
855 | {
856 | register struct rm *lev1, *lev2;
857 | struct trap *t;
858 | int x2, y2;
859 | boolean e_inview;
860 | struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]);
861 |
862 | lev1 = &levl[x][y];
863 | if (!IS_DRAWBRIDGE(lev1->typ))
864 | return;
865 | x2 = x; y2 = y;
866 | get_wall_for_db(&x2,&y2);
867 | lev2 = &levl[x2][y2];
868 | if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT ||
869 | (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) {
870 | struct obj *otmp;
871 | boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA;
872 | if (lev1->typ == DRAWBRIDGE_UP) {
873 | if (cansee(x2,y2))
874 | pline_The("portcullis of the drawbridge falls into the %s!",
875 | lava ? "lava" : "moat");
876 | else if (flags.soundok)
877 | You_hear("a loud *SPLASH*!");
878 | } else {
879 | if (cansee(x,y))
880 | pline_The("drawbridge collapses into the %s!",
881 | lava ? "lava" : "moat");
882 | else if (flags.soundok)
883 | You_hear("a loud *SPLASH*!");
884 | }
885 | lev1->typ = lava ? LAVAPOOL : MOAT;
886 | lev1->drawbridgemask = 0;
887 | if ((otmp = sobj_at(BOULDER,x,y)) != 0) {
888 | obj_extract_self(otmp);
889 | (void) flooreffects(otmp,x,y,"fall");
890 | }
891 | } else {
892 | if (cansee(x,y))
893 | pline_The("drawbridge disintegrates!");
894 | else
895 | You_hear("a loud *CRASH*!");
896 | lev1->typ =
897 | ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM);
898 | lev1->icedpool =
899 | ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0);
900 | }
901 | wake_nearto(x, y, 500);
902 | lev2->typ = DOOR;
903 | lev2->doormask = D_NODOOR;
904 | if ((t = t_at(x, y)) != 0) deltrap(t);
905 | if ((t = t_at(x2, y2)) != 0) deltrap(t);
906 | newsym(x,y);
907 | newsym(x2,y2);
908 | if (!does_block(x2,y2,lev2)) unblock_point(x2,y2); /* vision */
909 | if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE;
910 |
911 | set_entity(x2, y2, etmp2); /* currently only automissers can be here */
912 | if (etmp2->edata) {
913 | e_inview = e_canseemon(etmp2);
914 | if (!automiss(etmp2)) {
915 | if (e_inview)
916 | pline("%s blown apart by flying debris.",
917 | E_phrase(etmp2, "are"));
918 | killer_format = KILLED_BY_AN;
919 | killer = "exploding drawbridge";
920 | e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/
921 | } /* nothing which is vulnerable can survive this */
922 | }
923 | set_entity(x, y, etmp1);
924 | if (etmp1->edata) {
925 | e_inview = e_canseemon(etmp1);
926 | if (e_missed(etmp1, TRUE)) {
927 | #ifdef D_DEBUG
928 | pline("%s spared!", E_phrase(etmp1, "are"));
929 | #endif
930 | } else {
931 | if (e_inview) {
932 | if (!is_u(etmp1) && Hallucination)
933 | pline("%s into some heavy metal!",
934 | E_phrase(etmp1, "get"));
935 | else
936 | pline("%s hit by a huge chunk of metal!",
937 | E_phrase(etmp1, "are"));
938 | } else {
939 | if (flags.soundok && !is_u(etmp1) && !is_pool(x,y))
940 | You_hear("a crushing sound.");
941 | #ifdef D_DEBUG
942 | else
943 | pline("%s from shrapnel",
944 | E_phrase(etmp1, "die"));
945 | #endif
946 | }
947 | killer_format = KILLED_BY_AN;
948 | killer = "collapsing drawbridge";
949 | e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/
950 | if(lev1->typ == MOAT) do_entity(etmp1);
951 | }
952 | }
953 | }
954 |
955 | #endif /* OVLB */
956 |
957 | /*dbridge.c*/