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