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*/