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