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