1/* SCCS Id: @(#)dbridge.c 3.4 2003/02/08 */ 2/* Copyright (c) 1989 by Jean-Christophe Collet */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5/* 6 * This file contains the drawbridge manipulation (create, open, close, 7 * destroy). 8 * 9 * Added comprehensive monster-handling, and the "entity" structure to 10 * deal with players as well. - 11/89 11 */ 12 13#include "hack.h" 14 15#ifdef OVLB 16STATIC_DCL void FDECL(get_wall_for_db, (int *, int *)); 17STATIC_DCL struct entity *FDECL(e_at, (int, int)); 18STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *)); 19STATIC_DCL void FDECL(u_to_e, (struct entity *)); 20STATIC_DCL void FDECL(set_entity, (int, int, struct entity *)); 21STATIC_DCL const char *FDECL(e_nam, (struct entity *)); 22#ifdef D_DEBUG 23static const char *FDECL(Enam, (struct entity *)); /* unused */ 24#endif 25STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *)); 26STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int)); 27STATIC_DCL void FDECL(e_died, (struct entity *, int, int)); 28STATIC_DCL boolean FDECL(automiss, (struct entity *)); 29STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P)); 30STATIC_DCL boolean FDECL(e_jumps, (struct entity *)); 31STATIC_DCL void FDECL(do_entity, (struct entity *)); 32#endif /* OVLB */ 33 34#ifdef OVL0 35 36boolean 37is_pool(x,y) 38int 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 50boolean 51is_lava(x,y) 52int 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 64boolean 65is_ice(x,y) 66int 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 89int 90is_drawbridge_wall(x,y) 91int 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 */ 120boolean 121is_db_wall(x,y) 122int 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 */ 132boolean 133find_drawbridge(x,y) 134int *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 */ 159STATIC_OVL void 160get_wall_for_db(x,y) 161int *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 177boolean 178create_drawbridge(x,y,dir,flag) 179int x,y,dir; 180boolean 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 227struct 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 235static NEARDATA struct entity occupants[ENTITIES]; 236 237STATIC_OVL 238struct entity * 239e_at(x, y) 240int 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 257STATIC_OVL void 258m_to_e(mtmp, x, y, etmp) 259struct monst *mtmp; 260int x, y; 261struct 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 275STATIC_OVL void 276u_to_e(etmp) 277struct entity *etmp; 278{ 279 etmp->emon = &youmonst; 280 etmp->ex = u.ux; 281 etmp->ey = u.uy; 282 etmp->edata = youmonst.data; 283} 284 285STATIC_OVL void 286set_entity(x, y, etmp) 287int x, y; 288struct 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 308STATIC_OVL const char * 309e_nam(etmp) 310struct 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 320static const char * 321Enam(etmp) 322struct 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 333STATIC_OVL const char * 334E_phrase(etmp, verb) 335struct entity *etmp; 336const char *verb; 337{ 338 static char wholebuf[80]; 339 340 Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon)); 341 if (!*verb) return(wholebuf); 342 Strcat(wholebuf, " "); 343 if (is_u(etmp)) 344 Strcat(wholebuf, verb); 345 else 346 Strcat(wholebuf, vtense((char *)0, verb)); 347 return(wholebuf); 348} 349 350/* 351 * Simple-minded "can it be here?" routine 352 */ 353 354STATIC_OVL boolean 355e_survives_at(etmp, x, y) 356struct entity *etmp; 357int x, y; 358{ 359 if (noncorporeal(etmp->edata)) 360 return(TRUE); 361 if (is_pool(x, y)) 362 return (boolean)((is_u(etmp) && 363 (Wwalking || Amphibious || Swimming || 364 Flying || Levitation)) || 365 is_swimmer(etmp->edata) || is_flyer(etmp->edata) || 366 is_floater(etmp->edata)); 367 /* must force call to lava_effects in e_died if is_u */ 368 if (is_lava(x, y)) 369 return (boolean)((is_u(etmp) && (Levitation || Flying)) || 370 likes_lava(etmp->edata) || is_flyer(etmp->edata)); 371 if (is_db_wall(x, y)) 372 return((boolean)(is_u(etmp) ? Passes_walls : 373 passes_walls(etmp->edata))); 374 return(TRUE); 375} 376 377STATIC_OVL void 378e_died(etmp, dest, how) 379struct entity *etmp; 380int dest, how; 381{ 382 if (is_u(etmp)) { 383 if (how == DROWNING) { 384 killer = 0; /* drown() sets its own killer */ 385 (void) drown(); 386 } else if (how == BURNING) { 387 killer = 0; /* lava_effects() sets its own killer */ 388 (void) lava_effects(); 389 } else { 390 coord xy; 391 392 /* use more specific killer if specified */ 393 if (!killer) { 394 killer_format = KILLED_BY_AN; 395 killer = "falling drawbridge"; 396 } 397 done(how); 398 /* So, you didn't die */ 399 if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { 400 if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) { 401 pline("A %s force teleports you away...", 402 Hallucination ? "normal" : "strange"); 403 teleds(xy.x, xy.y, FALSE); 404 } 405 /* otherwise on top of the drawbridge is the 406 * only viable spot in the dungeon, so stay there 407 */ 408 } 409 } 410 /* we might have crawled out of the moat to survive */ 411 etmp->ex = u.ux, etmp->ey = u.uy; 412 } else { 413 int entitycnt; 414 415 killer = 0; 416 /* fake "digested to death" damage-type suppresses corpse */ 417#define mk_message(dest) ((dest & 1) ? "" : (char *)0) 418#define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS) 419 /* if monsters are moving, one of them caused the destruction */ 420 if (flags.mon_moving) 421 monkilled(etmp->emon, mk_message(dest), mk_corpse(dest)); 422 else /* you caused it */ 423 xkilled(etmp->emon, dest); 424 etmp->edata = (struct permonst *)0; 425 426 /* dead long worm handling */ 427 for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) { 428 if (etmp != &(occupants[entitycnt]) && 429 etmp->emon == occupants[entitycnt].emon) 430 occupants[entitycnt].edata = (struct permonst *)0; 431 } 432#undef mk_message 433#undef mk_corpse 434 } 435} 436 437 438/* 439 * These are never directly affected by a bridge or portcullis. 440 */ 441 442STATIC_OVL boolean 443automiss(etmp) 444struct entity *etmp; 445{ 446 return (boolean)((is_u(etmp) ? Passes_walls : 447 passes_walls(etmp->edata)) || noncorporeal(etmp->edata)); 448} 449 450/* 451 * Does falling drawbridge or portcullis miss etmp? 452 */ 453 454STATIC_OVL boolean 455e_missed(etmp, chunks) 456struct entity *etmp; 457boolean chunks; 458{ 459 int misses; 460 461#ifdef D_DEBUG 462 if (chunks) 463 pline("Do chunks miss?"); 464#endif 465 if (automiss(etmp)) 466 return(TRUE); 467 468 if (is_flyer(etmp->edata) && 469 (is_u(etmp)? !Sleeping : 470 (etmp->emon->mcanmove && !etmp->emon->msleeping))) 471 /* flying requires mobility */ 472 misses = 5; /* out of 8 */ 473 else if (is_floater(etmp->edata) || 474 (is_u(etmp) && Levitation)) /* doesn't require mobility */ 475 misses = 3; 476 else if (chunks && is_pool(etmp->ex, etmp->ey)) 477 misses = 2; /* sitting ducks */ 478 else 479 misses = 0; 480 481 if (is_db_wall(etmp->ex, etmp->ey)) 482 misses -= 3; /* less airspace */ 483 484#ifdef D_DEBUG 485 pline("Miss chance = %d (out of 8)", misses); 486#endif 487 488 return((boolean)((misses >= rnd(8))? TRUE : FALSE)); 489} 490 491/* 492 * Can etmp jump from death? 493 */ 494 495STATIC_OVL boolean 496e_jumps(etmp) 497struct entity *etmp; 498{ 499 int tmp = 4; /* out of 10 */ 500 501 if (is_u(etmp)? (Sleeping || Fumbling) : 502 (!etmp->emon->mcanmove || etmp->emon->msleeping || 503 !etmp->edata->mmove || etmp->emon->wormno)) 504 return(FALSE); 505 506 if (is_u(etmp)? Confusion : etmp->emon->mconf) 507 tmp -= 2; 508 509 if (is_u(etmp)? Stunned : etmp->emon->mstun) 510 tmp -= 3; 511 512 if (is_db_wall(etmp->ex, etmp->ey)) 513 tmp -= 2; /* less room to maneuver */ 514 515#ifdef D_DEBUG 516 pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp); 517#endif 518 return((boolean)((tmp >= rnd(10))? TRUE : FALSE)); 519} 520 521STATIC_OVL void 522do_entity(etmp) 523struct entity *etmp; 524{ 525 int newx, newy, at_portcullis, oldx, oldy; 526 boolean must_jump = FALSE, relocates = FALSE, e_inview; 527 struct rm *crm; 528 529 if (!etmp->edata) 530 return; 531 532 e_inview = e_canseemon(etmp); 533 oldx = etmp->ex; 534 oldy = etmp->ey; 535 at_portcullis = is_db_wall(oldx, oldy); 536 crm = &levl[oldx][oldy]; 537 538 if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) { 539 if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ))) 540 pline_The("%s passes through %s!", 541 at_portcullis ? "portcullis" : "drawbridge", 542 e_nam(etmp)); 543 if (is_u(etmp)) spoteffects(FALSE); 544 return; 545 } 546 if (e_missed(etmp, FALSE)) { 547 if (at_portcullis) 548 pline_The("portcullis misses %s!", 549 e_nam(etmp)); 550#ifdef D_DEBUG 551 else 552 pline_The("drawbridge misses %s!", 553 e_nam(etmp)); 554#endif 555 if (e_survives_at(etmp, oldx, oldy)) 556 return; 557 else { 558#ifdef D_DEBUG 559 pline("Mon can't survive here"); 560#endif 561 if (at_portcullis) 562 must_jump = TRUE; 563 else 564 relocates = TRUE; /* just ride drawbridge in */ 565 } 566 } else { 567 if (crm->typ == DRAWBRIDGE_DOWN) { 568 pline("%s crushed underneath the drawbridge.", 569 E_phrase(etmp, "are")); /* no jump */ 570 e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */ 571 return; /* Note: Beyond this point, we know we're */ 572 } /* not at an opened drawbridge, since all */ 573 must_jump = TRUE; /* *missable* creatures survive on the */ 574 } /* square, and all the unmissed ones die. */ 575 if (must_jump) { 576 if (at_portcullis) { 577 if (e_jumps(etmp)) { 578 relocates = TRUE; 579#ifdef D_DEBUG 580 pline("Jump succeeds!"); 581#endif 582 } else { 583 if (e_inview) 584 pline("%s crushed by the falling portcullis!", 585 E_phrase(etmp, "are")); 586 else if (flags.soundok) 587 You_hear("a crushing sound."); 588 e_died(etmp, e_inview? 3 : 2, CRUSHING); 589 /* no corpse */ 590 return; 591 } 592 } else { /* tries to jump off bridge to original square */ 593 relocates = !e_jumps(etmp); 594#ifdef D_DEBUG 595 pline("Jump %s!", (relocates)? "fails" : "succeeds"); 596#endif 597 } 598 } 599 600/* 601 * Here's where we try to do relocation. Assumes that etmp is not arriving 602 * at the portcullis square while the drawbridge is falling, since this square 603 * would be inaccessible (i.e. etmp started on drawbridge square) or 604 * unnecessary (i.e. etmp started here) in such a situation. 605 */ 606#ifdef D_DEBUG 607 pline("Doing relocation."); 608#endif 609 newx = oldx; 610 newy = oldy; 611 (void)find_drawbridge(&newx, &newy); 612 if ((newx == oldx) && (newy == oldy)) 613 get_wall_for_db(&newx, &newy); 614#ifdef D_DEBUG 615 pline("Checking new square for occupancy."); 616#endif 617 if (relocates && (e_at(newx, newy))) { 618 619/* 620 * Standoff problem: one or both entities must die, and/or both switch 621 * places. Avoid infinite recursion by checking first whether the other 622 * entity is staying put. Clean up if we happen to move/die in recursion. 623 */ 624 struct entity *other; 625 626 other = e_at(newx, newy); 627#ifdef D_DEBUG 628 pline("New square is occupied by %s", e_nam(other)); 629#endif 630 if (e_survives_at(other, newx, newy) && automiss(other)) { 631 relocates = FALSE; /* "other" won't budge */ 632#ifdef D_DEBUG 633 pline("%s suicide.", E_phrase(etmp, "commit")); 634#endif 635 } else { 636 637#ifdef D_DEBUG 638 pline("Handling %s", e_nam(other)); 639#endif 640 while ((e_at(newx, newy) != 0) && 641 (e_at(newx, newy) != etmp)) 642 do_entity(other); 643#ifdef D_DEBUG 644 pline("Checking existence of %s", e_nam(etmp)); 645 wait_synch(); 646#endif 647 if (e_at(oldx, oldy) != etmp) { 648#ifdef D_DEBUG 649 pline("%s moved or died in recursion somewhere", 650 E_phrase(etmp, "have")); 651 wait_synch(); 652#endif 653 return; 654 } 655 } 656 } 657 if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */ 658#ifdef D_DEBUG 659 pline("Moving %s", e_nam(etmp)); 660#endif 661 if (!is_u(etmp)) { 662 remove_monster(etmp->ex, etmp->ey); 663 place_monster(etmp->emon, newx, newy); 664 update_monster_region(etmp->emon); 665 } else { 666 u.ux = newx; 667 u.uy = newy; 668 } 669 etmp->ex = newx; 670 etmp->ey = newy; 671 e_inview = e_canseemon(etmp); 672 } 673#ifdef D_DEBUG 674 pline("Final disposition of %s", e_nam(etmp)); 675 wait_synch(); 676#endif 677 if (is_db_wall(etmp->ex, etmp->ey)) { 678#ifdef D_DEBUG 679 pline("%s in portcullis chamber", E_phrase(etmp, "are")); 680 wait_synch(); 681#endif 682 if (e_inview) { 683 if (is_u(etmp)) { 684 You("tumble towards the closed portcullis!"); 685 if (automiss(etmp)) 686 You("pass through it!"); 687 else 688 pline_The("drawbridge closes in..."); 689 } else 690 pline("%s behind the drawbridge.", 691 E_phrase(etmp, "disappear")); 692 } 693 if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { 694 killer_format = KILLED_BY_AN; 695 killer = "closing drawbridge"; 696 e_died(etmp, 0, CRUSHING); /* no message */ 697 return; 698 } 699#ifdef D_DEBUG 700 pline("%s in here", E_phrase(etmp, "survive")); 701#endif 702 } else { 703#ifdef D_DEBUG 704 pline("%s on drawbridge square", E_phrase(etmp, "are")); 705#endif 706 if (is_pool(etmp->ex, etmp->ey) && !e_inview) 707 if (flags.soundok) 708 You_hear("a splash."); 709 if (e_survives_at(etmp, etmp->ex, etmp->ey)) { 710 if (e_inview && !is_flyer(etmp->edata) && 711 !is_floater(etmp->edata)) 712 pline("%s from the bridge.", 713 E_phrase(etmp, "fall")); 714 return; 715 } 716#ifdef D_DEBUG 717 pline("%s cannot survive on the drawbridge square",Enam(etmp)); 718#endif 719 if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey)) 720 if (e_inview && !is_u(etmp)) { 721 /* drown() will supply msgs if nec. */ 722 boolean lava = is_lava(etmp->ex, etmp->ey); 723 724 if (Hallucination) 725 pline("%s the %s and disappears.", 726 E_phrase(etmp, "drink"), 727 lava ? "lava" : "moat"); 728 else 729 pline("%s into the %s.", 730 E_phrase(etmp, "fall"), 731 lava ? "lava" : "moat"); 732 } 733 killer_format = NO_KILLER_PREFIX; 734 killer = "fell from a drawbridge"; 735 e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */ 736 (is_pool(etmp->ex, etmp->ey)) ? DROWNING : 737 (is_lava(etmp->ex, etmp->ey)) ? BURNING : 738 CRUSHING); /*no corpse*/ 739 return; 740 } 741} 742 743/* 744 * Close the drawbridge located at x,y 745 */ 746 747void 748close_drawbridge(x,y) 749int x,y; 750{ 751 register struct rm *lev1, *lev2; 752 struct trap *t; 753 int x2, y2; 754 755 lev1 = &levl[x][y]; 756 if (lev1->typ != DRAWBRIDGE_DOWN) return; 757 x2 = x; y2 = y; 758 get_wall_for_db(&x2,&y2); 759 if (cansee(x,y) || cansee(x2,y2)) 760 You("see a drawbridge %s up!", 761 (((u.ux == x || u.uy == y) && !Underwater) || 762 distu(x2,y2) < distu(x,y)) ? "coming" : "going"); 763 lev1->typ = DRAWBRIDGE_UP; 764 lev2 = &levl[x2][y2]; 765 lev2->typ = DBWALL; 766 switch (lev1->drawbridgemask & DB_DIR) { 767 case DB_NORTH: 768 case DB_SOUTH: 769 lev2->horizontal = TRUE; 770 break; 771 case DB_WEST: 772 case DB_EAST: 773 lev2->horizontal = FALSE; 774 break; 775 } 776 lev2->wall_info = W_NONDIGGABLE; 777 set_entity(x, y, &(occupants[0])); 778 set_entity(x2, y2, &(occupants[1])); 779 do_entity(&(occupants[0])); /* Do set_entity after first */ 780 set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */ 781 do_entity(&(occupants[1])); 782 if(OBJ_AT(x,y) && flags.soundok) 783 You_hear("smashing and crushing."); 784 (void) revive_nasty(x,y,(char *)0); 785 (void) revive_nasty(x2,y2,(char *)0); 786 delallobj(x, y); 787 delallobj(x2, y2); 788 if ((t = t_at(x, y)) != 0) deltrap(t); 789 if ((t = t_at(x2, y2)) != 0) deltrap(t); 790 newsym(x, y); 791 newsym(x2, y2); 792 block_point(x2,y2); /* vision */ 793} 794 795/* 796 * Open the drawbridge located at x,y 797 */ 798 799void 800open_drawbridge(x,y) 801int x,y; 802{ 803 register struct rm *lev1, *lev2; 804 struct trap *t; 805 int x2, y2; 806 807 lev1 = &levl[x][y]; 808 if (lev1->typ != DRAWBRIDGE_UP) return; 809 x2 = x; y2 = y; 810 get_wall_for_db(&x2,&y2); 811 if (cansee(x,y) || cansee(x2,y2)) 812 You("see a drawbridge %s down!", 813 (distu(x2,y2) < distu(x,y)) ? "going" : "coming"); 814 lev1->typ = DRAWBRIDGE_DOWN; 815 lev2 = &levl[x2][y2]; 816 lev2->typ = DOOR; 817 lev2->doormask = D_NODOOR; 818 set_entity(x, y, &(occupants[0])); 819 set_entity(x2, y2, &(occupants[1])); 820 do_entity(&(occupants[0])); /* do set_entity after first */ 821 set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */ 822 do_entity(&(occupants[1])); 823 (void) revive_nasty(x,y,(char *)0); 824 delallobj(x, y); 825 if ((t = t_at(x, y)) != 0) deltrap(t); 826 if ((t = t_at(x2, y2)) != 0) deltrap(t); 827 newsym(x, y); 828 newsym(x2, y2); 829 unblock_point(x2,y2); /* vision */ 830 if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; 831} 832 833/* 834 * Let's destroy the drawbridge located at x,y 835 */ 836 837void 838destroy_drawbridge(x,y) 839int x,y; 840{ 841 register struct rm *lev1, *lev2; 842 struct trap *t; 843 int x2, y2; 844 boolean e_inview; 845 struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); 846 847 lev1 = &levl[x][y]; 848 if (!IS_DRAWBRIDGE(lev1->typ)) 849 return; 850 x2 = x; y2 = y; 851 get_wall_for_db(&x2,&y2); 852 lev2 = &levl[x2][y2]; 853 if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT || 854 (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) { 855 struct obj *otmp; 856 boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA; 857 if (lev1->typ == DRAWBRIDGE_UP) { 858 if (cansee(x2,y2)) 859 pline_The("portcullis of the drawbridge falls into the %s!", 860 lava ? "lava" : "moat"); 861 else if (flags.soundok) 862 You_hear("a loud *SPLASH*!"); 863 } else { 864 if (cansee(x,y)) 865 pline_The("drawbridge collapses into the %s!", 866 lava ? "lava" : "moat"); 867 else if (flags.soundok) 868 You_hear("a loud *SPLASH*!"); 869 } 870 lev1->typ = lava ? LAVAPOOL : MOAT; 871 lev1->drawbridgemask = 0; 872 if ((otmp = sobj_at(BOULDER,x,y)) != 0) { 873 obj_extract_self(otmp); 874 (void) flooreffects(otmp,x,y,"fall"); 875 } 876 } else { 877 if (cansee(x,y)) 878 pline_The("drawbridge disintegrates!"); 879 else 880 You_hear("a loud *CRASH*!"); 881 lev1->typ = 882 ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM); 883 lev1->icedpool = 884 ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); 885 } 886 wake_nearto(x, y, 500); 887 lev2->typ = DOOR; 888 lev2->doormask = D_NODOOR; 889 if ((t = t_at(x, y)) != 0) deltrap(t); 890 if ((t = t_at(x2, y2)) != 0) deltrap(t); 891 newsym(x,y); 892 newsym(x2,y2); 893 if (!does_block(x2,y2,lev2)) unblock_point(x2,y2); /* vision */ 894 if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; 895 896 set_entity(x2, y2, etmp2); /* currently only automissers can be here */ 897 if (etmp2->edata) { 898 e_inview = e_canseemon(etmp2); 899 if (!automiss(etmp2)) { 900 if (e_inview) 901 pline("%s blown apart by flying debris.", 902 E_phrase(etmp2, "are")); 903 killer_format = KILLED_BY_AN; 904 killer = "exploding drawbridge"; 905 e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/ 906 } /* nothing which is vulnerable can survive this */ 907 } 908 set_entity(x, y, etmp1); 909 if (etmp1->edata) { 910 e_inview = e_canseemon(etmp1); 911 if (e_missed(etmp1, TRUE)) { 912#ifdef D_DEBUG 913 pline("%s spared!", E_phrase(etmp1, "are")); 914#endif 915 } else { 916 if (e_inview) { 917 if (!is_u(etmp1) && Hallucination) 918 pline("%s into some heavy metal!", 919 E_phrase(etmp1, "get")); 920 else 921 pline("%s hit by a huge chunk of metal!", 922 E_phrase(etmp1, "are")); 923 } else { 924 if (flags.soundok && !is_u(etmp1) && !is_pool(x,y)) 925 You_hear("a crushing sound."); 926#ifdef D_DEBUG 927 else 928 pline("%s from shrapnel", 929 E_phrase(etmp1, "die")); 930#endif 931 } 932 killer_format = KILLED_BY_AN; 933 killer = "collapsing drawbridge"; 934 e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/ 935 if(lev1->typ == MOAT) do_entity(etmp1); 936 } 937 } 938} 939 940#endif /* OVLB */ 941 942/*dbridge.c*/ 943