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