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