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