1 /* $NetBSD: hack.zap.c,v 1.5 2001/03/25 20:44:04 jsm Exp $ */ 2 3 /* 4 * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. 5 */ 6 7 #include <sys/cdefs.h> 8 #ifndef lint 9 __RCSID("$NetBSD: hack.zap.c,v 1.5 2001/03/25 20:44:04 jsm Exp $"); 10 #endif /* not lint */ 11 12 #include "hack.h" 13 #include "extern.h" 14 15 const char *const fl[] = { 16 "magic missile", 17 "bolt of fire", 18 "sleep ray", 19 "bolt of cold", 20 "death ray" 21 }; 22 23 /* Routines for IMMEDIATE wands. */ 24 /* bhitm: monster mtmp was hit by the effect of wand otmp */ 25 void 26 bhitm(mtmp, otmp) 27 struct monst *mtmp; 28 struct obj *otmp; 29 { 30 wakeup(mtmp); 31 switch (otmp->otyp) { 32 case WAN_STRIKING: 33 if (u.uswallow || rnd(20) < 10 + mtmp->data->ac) { 34 int tmp = d(2, 12); 35 hit("wand", mtmp, exclam(tmp)); 36 mtmp->mhp -= tmp; 37 if (mtmp->mhp < 1) 38 killed(mtmp); 39 } else 40 miss("wand", mtmp); 41 break; 42 case WAN_SLOW_MONSTER: 43 mtmp->mspeed = MSLOW; 44 break; 45 case WAN_SPEED_MONSTER: 46 mtmp->mspeed = MFAST; 47 break; 48 case WAN_UNDEAD_TURNING: 49 if (strchr(UNDEAD, mtmp->data->mlet)) { 50 mtmp->mhp -= rnd(8); 51 if (mtmp->mhp < 1) 52 killed(mtmp); 53 else 54 mtmp->mflee = 1; 55 } 56 break; 57 case WAN_POLYMORPH: 58 if (newcham(mtmp, &mons[rn2(CMNUM)])) 59 objects[otmp->otyp].oc_name_known = 1; 60 break; 61 case WAN_CANCELLATION: 62 mtmp->mcan = 1; 63 break; 64 case WAN_TELEPORTATION: 65 rloc(mtmp); 66 break; 67 case WAN_MAKE_INVISIBLE: 68 mtmp->minvis = 1; 69 break; 70 #ifdef WAN_PROBING 71 case WAN_PROBING: 72 mstatusline(mtmp); 73 break; 74 #endif /* WAN_PROBING */ 75 default: 76 impossible("What an interesting wand (%u)", otmp->otyp); 77 } 78 } 79 80 int 81 bhito(obj, otmp) /* object obj was hit by the effect of wand 82 * otmp */ 83 struct obj *obj, *otmp; /* returns TRUE if sth was done */ 84 { 85 int res = TRUE; 86 87 if (obj == uball || obj == uchain) 88 res = FALSE; 89 else 90 switch (otmp->otyp) { 91 case WAN_POLYMORPH: 92 /* 93 * preserve symbol and quantity, but turn rocks into 94 * gems 95 */ 96 mkobj_at((obj->otyp == ROCK || obj->otyp == ENORMOUS_ROCK) 97 ? GEM_SYM : obj->olet, 98 obj->ox, obj->oy)->quan = obj->quan; 99 delobj(obj); 100 break; 101 case WAN_STRIKING: 102 if (obj->otyp == ENORMOUS_ROCK) 103 fracture_rock(obj); 104 else 105 res = FALSE; 106 break; 107 case WAN_CANCELLATION: 108 if (obj->spe && obj->olet != AMULET_SYM) { 109 obj->known = 0; 110 obj->spe = 0; 111 } 112 break; 113 case WAN_TELEPORTATION: 114 rloco(obj); 115 break; 116 case WAN_MAKE_INVISIBLE: 117 obj->oinvis = 1; 118 break; 119 case WAN_UNDEAD_TURNING: 120 res = revive(obj); 121 break; 122 case WAN_SLOW_MONSTER: /* no effect on objects */ 123 case WAN_SPEED_MONSTER: 124 #ifdef WAN_PROBING 125 case WAN_PROBING: 126 #endif /* WAN_PROBING */ 127 res = FALSE; 128 break; 129 default: 130 impossible("What an interesting wand (%u)", otmp->otyp); 131 } 132 return (res); 133 } 134 135 int 136 dozap() 137 { 138 struct obj *obj; 139 xchar zx, zy; 140 141 obj = getobj("/", "zap"); 142 if (!obj) 143 return (0); 144 if (obj->spe < 0 || (obj->spe == 0 && rn2(121))) { 145 pline("Nothing Happens."); 146 return (1); 147 } 148 if (obj->spe == 0) 149 pline("You wrest one more spell from the worn-out wand."); 150 if (!(objects[obj->otyp].bits & NODIR) && !getdir(1)) 151 return (1); /* make him pay for knowing !NODIR */ 152 obj->spe--; 153 if (objects[obj->otyp].bits & IMMEDIATE) { 154 if (u.uswallow) 155 bhitm(u.ustuck, obj); 156 else if (u.dz) { 157 if (u.dz > 0) { 158 struct obj *otmp = o_at(u.ux, u.uy); 159 if (otmp) 160 (void) bhito(otmp, obj); 161 } 162 } else 163 (void) bhit(u.dx, u.dy, rn1(8, 6), 0, bhitm, bhito, obj); 164 } else { 165 switch (obj->otyp) { 166 case WAN_LIGHT: 167 litroom(TRUE); 168 break; 169 case WAN_SECRET_DOOR_DETECTION: 170 if (!findit()) 171 return (1); 172 break; 173 case WAN_CREATE_MONSTER: 174 { 175 int cnt = 1; 176 if (!rn2(23)) 177 cnt += rn2(7) + 1; 178 while (cnt--) 179 (void) makemon((struct permonst *) 0, u.ux, u.uy); 180 } 181 break; 182 case WAN_WISHING: 183 { 184 char buf[BUFSZ]; 185 struct obj *otmp; 186 if (u.uluck + rn2(5) < 0) { 187 pline("Unfortunately, nothing happens."); 188 break; 189 } 190 pline("You may wish for an object. What do you want? "); 191 getlin(buf); 192 if (buf[0] == '\033') 193 buf[0] = 0; 194 otmp = readobjnam(buf); 195 otmp = addinv(otmp); 196 prinv(otmp); 197 break; 198 } 199 case WAN_DIGGING: 200 /* 201 * Original effect (approximately): from CORR: dig 202 * until we pierce a wall from ROOM: piece wall and 203 * dig until we reach an ACCESSIBLE place. Currently: 204 * dig for digdepth positions; also down on request 205 * of Lennart Augustsson. 206 */ 207 { 208 struct rm *room; 209 int digdepth; 210 if (u.uswallow) { 211 struct monst *mtmp = u.ustuck; 212 213 pline("You pierce %s's stomach wall!", 214 monnam(mtmp)); 215 mtmp->mhp = 1; /* almost dead */ 216 unstuck(mtmp); 217 mnexto(mtmp); 218 break; 219 } 220 if (u.dz) { 221 if (u.dz < 0) { 222 pline("You loosen a rock from the ceiling."); 223 pline("It falls on your head!"); 224 losehp(1, "falling rock"); 225 mksobj_at(ROCK, u.ux, u.uy); 226 fobj->quan = 1; 227 stackobj(fobj); 228 if (Invisible) 229 newsym(u.ux, u.uy); 230 } else { 231 dighole(); 232 } 233 break; 234 } 235 zx = u.ux + u.dx; 236 zy = u.uy + u.dy; 237 digdepth = 8 + rn2(18); 238 Tmp_at(-1, '*'); /* open call */ 239 while (--digdepth >= 0) { 240 if (!isok(zx, zy)) 241 break; 242 room = &levl[zx][zy]; 243 Tmp_at(zx, zy); 244 if (!xdnstair) { 245 if (zx < 3 || zx > COLNO - 3 || 246 zy < 3 || zy > ROWNO - 3) 247 break; 248 if (room->typ == HWALL || 249 room->typ == VWALL) { 250 room->typ = ROOM; 251 break; 252 } 253 } else if (room->typ == HWALL || room->typ == VWALL || 254 room->typ == SDOOR || room->typ == LDOOR) { 255 room->typ = DOOR; 256 digdepth -= 2; 257 } else if (room->typ == SCORR || !room->typ) { 258 room->typ = CORR; 259 digdepth--; 260 } 261 mnewsym(zx, zy); 262 zx += u.dx; 263 zy += u.dy; 264 } 265 mnewsym(zx, zy); /* not always necessary */ 266 Tmp_at(-1, -1); /* closing call */ 267 break; 268 } 269 default: 270 buzz((int) obj->otyp - WAN_MAGIC_MISSILE, 271 u.ux, u.uy, u.dx, u.dy); 272 break; 273 } 274 if (!objects[obj->otyp].oc_name_known) { 275 objects[obj->otyp].oc_name_known = 1; 276 more_experienced(0, 10); 277 } 278 } 279 return (1); 280 } 281 282 const char * 283 exclam(force) 284 int force; 285 { 286 /* force == 0 occurs e.g. with sleep ray */ 287 /* 288 * note that large force is usual with wands so that !! would require 289 * information about hand/weapon/wand 290 */ 291 return ((force < 0) ? "?" : (force <= 4) ? "." : "!"); 292 } 293 294 void 295 hit(str, mtmp, force) 296 const char *str; 297 struct monst *mtmp; 298 const char *force; /* usually either "." or "!" */ 299 { 300 if (!cansee(mtmp->mx, mtmp->my)) 301 pline("The %s hits it.", str); 302 else 303 pline("The %s hits %s%s", str, monnam(mtmp), force); 304 } 305 306 void 307 miss(str, mtmp) 308 const char *str; 309 struct monst *mtmp; 310 { 311 if (!cansee(mtmp->mx, mtmp->my)) 312 pline("The %s misses it.", str); 313 else 314 pline("The %s misses %s.", str, monnam(mtmp)); 315 } 316 317 /* 318 * bhit: called when a weapon is thrown (sym = obj->olet) or when an 319 * IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of range 320 * or when a monster is hit; the monster is returned, and bhitpos is set to 321 * the final position of the weapon thrown; the ray of a wand may affect 322 * several objects and monsters on its path - for each of these an argument 323 * function is called. 324 */ 325 /* check !u.uswallow before calling bhit() */ 326 327 struct monst * 328 bhit(ddx, ddy, range, sym, fhitm, fhito, obj) 329 int ddx, ddy, range; /* direction and range */ 330 char sym; /* symbol displayed on path */ 331 /* fns called when mon/obj hit */ 332 void (*fhitm) __P((struct monst *, struct obj *)); 333 int (*fhito) __P((struct obj *, struct obj *)); 334 struct obj *obj; /* 2nd arg to fhitm/fhito */ 335 { 336 struct monst *mtmp; 337 struct obj *otmp; 338 int typ; 339 340 bhitpos.x = u.ux; 341 bhitpos.y = u.uy; 342 343 if (sym) 344 tmp_at(-1, sym);/* open call */ 345 while (range-- > 0) { 346 bhitpos.x += ddx; 347 bhitpos.y += ddy; 348 typ = levl[bhitpos.x][bhitpos.y].typ; 349 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) { 350 if (sym) { 351 tmp_at(-1, -1); /* close call */ 352 return (mtmp); 353 } 354 (*fhitm) (mtmp, obj); 355 range -= 3; 356 } 357 if (fhito && (otmp = o_at(bhitpos.x, bhitpos.y))) { 358 if ((*fhito) (otmp, obj)) 359 range--; 360 } 361 if (!ZAP_POS(typ)) { 362 bhitpos.x -= ddx; 363 bhitpos.y -= ddy; 364 break; 365 } 366 if (sym) 367 tmp_at(bhitpos.x, bhitpos.y); 368 } 369 370 /* leave last symbol unless in a pool */ 371 if (sym) 372 tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0); 373 return (0); 374 } 375 376 struct monst * 377 boomhit(int dx, int dy) 378 { 379 int i, ct; 380 struct monst *mtmp; 381 char sym = ')'; 382 383 bhitpos.x = u.ux; 384 bhitpos.y = u.uy; 385 386 for (i = 0; i < 8; i++) 387 if (xdir[i] == dx && ydir[i] == dy) 388 break; 389 tmp_at(-1, sym); /* open call */ 390 for (ct = 0; ct < 10; ct++) { 391 if (i == 8) 392 i = 0; 393 sym = ')' + '(' - sym; 394 tmp_at(-2, sym);/* change let call */ 395 dx = xdir[i]; 396 dy = ydir[i]; 397 bhitpos.x += dx; 398 bhitpos.y += dy; 399 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) { 400 tmp_at(-1, -1); 401 return (mtmp); 402 } 403 if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) { 404 bhitpos.x -= dx; 405 bhitpos.y -= dy; 406 break; 407 } 408 if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */ 409 if (rn2(20) >= 10 + u.ulevel) { /* we hit ourselves */ 410 (void) thitu(10, rnd(10), "boomerang"); 411 break; 412 } else {/* we catch it */ 413 tmp_at(-1, -1); 414 pline("Skillfully, you catch the boomerang."); 415 return (&youmonst); 416 } 417 } 418 tmp_at(bhitpos.x, bhitpos.y); 419 if (ct % 5 != 0) 420 i++; 421 } 422 tmp_at(-1, -1); /* do not leave last symbol */ 423 return (0); 424 } 425 426 char 427 dirlet(dx, dy) 428 int dx, dy; 429 { 430 return 431 (dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|'; 432 } 433 434 /* type == -1: monster spitting fire at you */ 435 /* type == -1,-2,-3: bolts sent out by wizard */ 436 /* called with dx = dy = 0 with vertical bolts */ 437 void 438 buzz(type, sx, sy, dx, dy) 439 int type; 440 xchar sx, sy; 441 int dx, dy; 442 { 443 int abstype = abs(type); 444 const char *fltxt = (type == -1) ? "blaze of fire" : fl[abstype]; 445 struct rm *lev; 446 xchar range; 447 struct monst *mon; 448 449 if (u.uswallow) { 450 int tmp; 451 452 if (type < 0) 453 return; 454 tmp = zhit(u.ustuck, type); 455 pline("The %s rips into %s%s", 456 fltxt, monnam(u.ustuck), exclam(tmp)); 457 return; 458 } 459 if (type < 0) 460 pru(); 461 range = rn1(7, 7); 462 Tmp_at(-1, dirlet(dx, dy)); /* open call */ 463 while (range-- > 0) { 464 sx += dx; 465 sy += dy; 466 if ((lev = &levl[sx][sy])->typ) 467 Tmp_at(sx, sy); 468 else { 469 int bounce = 0; 470 if (cansee(sx - dx, sy - dy)) 471 pline("The %s bounces!", fltxt); 472 if (ZAP_POS(levl[sx][sy - dy].typ)) 473 bounce = 1; 474 if (ZAP_POS(levl[sx - dx][sy].typ)) { 475 if (!bounce || rn2(2)) 476 bounce = 2; 477 } 478 switch (bounce) { 479 case 0: 480 dx = -dx; 481 dy = -dy; 482 continue; 483 case 1: 484 dy = -dy; 485 sx -= dx; 486 break; 487 case 2: 488 dx = -dx; 489 sy -= dy; 490 break; 491 } 492 Tmp_at(-2, dirlet(dx, dy)); 493 continue; 494 } 495 if (lev->typ == POOL && abstype == 1 /* fire */ ) { 496 range -= 3; 497 lev->typ = ROOM; 498 if (cansee(sx, sy)) { 499 mnewsym(sx, sy); 500 pline("The water evaporates."); 501 } else 502 pline("You hear a hissing sound."); 503 } 504 if ((mon = m_at(sx, sy)) && 505 (type != -1 || mon->data->mlet != 'D')) { 506 wakeup(mon); 507 if (rnd(20) < 18 + mon->data->ac) { 508 int tmp = zhit(mon, abstype); 509 if (mon->mhp < 1) { 510 if (type < 0) { 511 if (cansee(mon->mx, mon->my)) 512 pline("%s is killed by the %s!", 513 Monnam(mon), fltxt); 514 mondied(mon); 515 } else 516 killed(mon); 517 } else 518 hit(fltxt, mon, exclam(tmp)); 519 range -= 2; 520 } else 521 miss(fltxt, mon); 522 } else if (sx == u.ux && sy == u.uy) { 523 nomul(0); 524 if (rnd(20) < 18 + u.uac) { 525 int dam = 0; 526 range -= 2; 527 pline("The %s hits you!", fltxt); 528 switch (abstype) { 529 case 0: 530 dam = d(2, 6); 531 break; 532 case 1: 533 if (Fire_resistance) 534 pline("You don't feel hot!"); 535 else 536 dam = d(6, 6); 537 if (!rn2(3)) 538 burn_scrolls(); 539 break; 540 case 2: 541 nomul(-rnd(25)); /* sleep ray */ 542 break; 543 case 3: 544 if (Cold_resistance) 545 pline("You don't feel cold!"); 546 else 547 dam = d(6, 6); 548 break; 549 case 4: 550 u.uhp = -1; 551 } 552 losehp(dam, fltxt); 553 } else 554 pline("The %s whizzes by you!", fltxt); 555 stop_occupation(); 556 } 557 if (!ZAP_POS(lev->typ)) { 558 int bounce = 0, rmn; 559 if (cansee(sx, sy)) 560 pline("The %s bounces!", fltxt); 561 range--; 562 if (!dx || !dy || !rn2(20)) { 563 dx = -dx; 564 dy = -dy; 565 } else { 566 if (ZAP_POS(rmn = levl[sx][sy - dy].typ) && 567 (IS_ROOM(rmn) || ZAP_POS(levl[sx + dx][sy - dy].typ))) 568 bounce = 1; 569 if (ZAP_POS(rmn = levl[sx - dx][sy].typ) && 570 (IS_ROOM(rmn) || ZAP_POS(levl[sx - dx][sy + dy].typ))) 571 if (!bounce || rn2(2)) 572 bounce = 2; 573 574 switch (bounce) { 575 case 0: 576 dy = -dy; 577 dx = -dx; 578 break; 579 case 1: 580 dy = -dy; 581 break; 582 case 2: 583 dx = -dx; 584 break; 585 } 586 Tmp_at(-2, dirlet(dx, dy)); 587 } 588 } 589 } 590 Tmp_at(-1, -1); 591 } 592 593 int 594 zhit(mon, type) /* returns damage to mon */ 595 struct monst *mon; 596 int type; 597 { 598 int tmp = 0; 599 600 switch (type) { 601 case 0: /* magic missile */ 602 tmp = d(2, 6); 603 break; 604 case -1: /* Dragon blazing fire */ 605 case 1: /* fire */ 606 if (strchr("Dg", mon->data->mlet)) 607 break; 608 tmp = d(6, 6); 609 if (strchr("YF", mon->data->mlet)) 610 tmp += 7; 611 break; 612 case 2: /* sleep */ 613 mon->mfroz = 1; 614 break; 615 case 3: /* cold */ 616 if (strchr("YFgf", mon->data->mlet)) 617 break; 618 tmp = d(6, 6); 619 if (mon->data->mlet == 'D') 620 tmp += 7; 621 break; 622 case 4: /* death */ 623 if (strchr(UNDEAD, mon->data->mlet)) 624 break; 625 tmp = mon->mhp + 1; 626 break; 627 } 628 mon->mhp -= tmp; 629 return (tmp); 630 } 631 632 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\ 633 ? 'a' + (otyp - DEAD_ACID_BLOB)\ 634 : '@' + (otyp - DEAD_HUMAN)) 635 int 636 revive(obj) 637 struct obj *obj; 638 { 639 struct monst *mtmp = NULL; 640 641 if (obj->olet == FOOD_SYM && obj->otyp > CORPSE) { 642 /* do not (yet) revive shopkeepers */ 643 /* 644 * Note: this might conceivably produce two monsters at the 645 * same position - strange, but harmless 646 */ 647 mtmp = mkmon_at(CORPSE_I_TO_C(obj->otyp), obj->ox, obj->oy); 648 delobj(obj); 649 } 650 return (!!mtmp); /* TRUE if some monster created */ 651 } 652 653 void 654 rloco(obj) 655 struct obj *obj; 656 { 657 int tx, ty, otx, oty; 658 659 otx = obj->ox; 660 oty = obj->oy; 661 do { 662 tx = rn1(COLNO - 3, 2); 663 ty = rn2(ROWNO); 664 } while (!goodpos(tx, ty)); 665 obj->ox = tx; 666 obj->oy = ty; 667 if (cansee(otx, oty)) 668 newsym(otx, oty); 669 } 670 671 void 672 fracture_rock(obj) /* fractured by pick-axe or wand of striking */ 673 struct obj *obj; /* no texts here! */ 674 { 675 /* unpobj(obj); */ 676 obj->otyp = ROCK; 677 obj->quan = 7 + rn2(60); 678 obj->owt = weight(obj); 679 obj->olet = WEAPON_SYM; 680 if (cansee(obj->ox, obj->oy)) 681 prl(obj->ox, obj->oy); 682 } 683 684 void 685 burn_scrolls() 686 { 687 struct obj *obj, *obj2; 688 int cnt = 0; 689 690 for (obj = invent; obj; obj = obj2) { 691 obj2 = obj->nobj; 692 if (obj->olet == SCROLL_SYM) { 693 cnt++; 694 useup(obj); 695 } 696 } 697 if (cnt > 1) { 698 pline("Your scrolls catch fire!"); 699 losehp(cnt, "burning scrolls"); 700 } else if (cnt) { 701 pline("Your scroll catches fire!"); 702 losehp(1, "burning scroll"); 703 } 704 } 705