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