1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 2: /* hack.zap.c - version 1.0.3 */ 3: 4: #include "hack.h" 5: 6: extern struct obj *mkobj_at(); 7: extern struct monst *makemon(), *mkmon_at(), youmonst; 8: struct monst *bhit(); 9: char *exclam(); 10: 11: char *fl[]= { 12: "magic missile", 13: "bolt of fire", 14: "sleep ray", 15: "bolt of cold", 16: "death ray" 17: }; 18: 19: /* Routines for IMMEDIATE wands. */ 20: /* bhitm: monster mtmp was hit by the effect of wand otmp */ 21: bhitm(mtmp, otmp) 22: register struct monst *mtmp; 23: register struct obj *otmp; 24: { 25: wakeup(mtmp); 26: switch(otmp->otyp) { 27: case WAN_STRIKING: 28: if(u.uswallow || rnd(20) < 10+mtmp->data->ac) { 29: register int tmp = d(2,12); 30: hit("wand", mtmp, exclam(tmp)); 31: mtmp->mhp -= tmp; 32: if(mtmp->mhp < 1) killed(mtmp); 33: } else miss("wand", mtmp); 34: break; 35: case WAN_SLOW_MONSTER: 36: mtmp->mspeed = MSLOW; 37: break; 38: case WAN_SPEED_MONSTER: 39: mtmp->mspeed = MFAST; 40: break; 41: case WAN_UNDEAD_TURNING: 42: if(index(UNDEAD,mtmp->data->mlet)) { 43: mtmp->mhp -= rnd(8); 44: if(mtmp->mhp < 1) killed(mtmp); 45: else mtmp->mflee = 1; 46: } 47: break; 48: case WAN_POLYMORPH: 49: if( newcham(mtmp,&mons[rn2(CMNUM)]) ) 50: objects[otmp->otyp].oc_name_known = 1; 51: break; 52: case WAN_CANCELLATION: 53: mtmp->mcan = 1; 54: break; 55: case WAN_TELEPORTATION: 56: rloc(mtmp); 57: break; 58: case WAN_MAKE_INVISIBLE: 59: mtmp->minvis = 1; 60: break; 61: #ifdef WAN_PROBING 62: case WAN_PROBING: 63: mstatusline(mtmp); 64: break; 65: #endif WAN_PROBING 66: default: 67: impossible("What an interesting wand (%u)", otmp->otyp); 68: } 69: } 70: 71: bhito(obj, otmp) /* object obj was hit by the effect of wand otmp */ 72: register struct obj *obj, *otmp; /* returns TRUE if sth was done */ 73: { 74: register int res = TRUE; 75: 76: if(obj == uball || obj == uchain) 77: res = FALSE; 78: else 79: switch(otmp->otyp) { 80: case WAN_POLYMORPH: 81: /* preserve symbol and quantity, but turn rocks into gems */ 82: mkobj_at((obj->otyp == ROCK || obj->otyp == ENORMOUS_ROCK) 83: ? GEM_SYM : obj->olet, 84: obj->ox, obj->oy) -> quan = obj->quan; 85: delobj(obj); 86: break; 87: case WAN_STRIKING: 88: if(obj->otyp == ENORMOUS_ROCK) 89: fracture_rock(obj); 90: else 91: res = FALSE; 92: break; 93: case WAN_CANCELLATION: 94: if(obj->spe && obj->olet != AMULET_SYM) { 95: obj->known = 0; 96: obj->spe = 0; 97: } 98: break; 99: case WAN_TELEPORTATION: 100: rloco(obj); 101: break; 102: case WAN_MAKE_INVISIBLE: 103: obj->oinvis = 1; 104: break; 105: case WAN_UNDEAD_TURNING: 106: res = revive(obj); 107: break; 108: case WAN_SLOW_MONSTER: /* no effect on objects */ 109: case WAN_SPEED_MONSTER: 110: #ifdef WAN_PROBING 111: case WAN_PROBING: 112: #endif WAN_PROBING 113: res = FALSE; 114: break; 115: default: 116: impossible("What an interesting wand (%u)", otmp->otyp); 117: } 118: return(res); 119: } 120: 121: dozap() 122: { 123: register struct obj *obj; 124: xchar zx,zy; 125: 126: obj = getobj("/", "zap"); 127: if(!obj) return(0); 128: if(obj->spe < 0 || (obj->spe == 0 && rn2(121))) { 129: pline("Nothing Happens."); 130: return(1); 131: } 132: if(obj->spe == 0) 133: pline("You wrest one more spell from the worn-out wand."); 134: if(!(objects[obj->otyp].bits & NODIR) && !getdir(1)) 135: return(1); /* make him pay for knowing !NODIR */ 136: obj->spe--; 137: if(objects[obj->otyp].bits & IMMEDIATE) { 138: if(u.uswallow) 139: bhitm(u.ustuck, obj); 140: else if(u.dz) { 141: if(u.dz > 0) { 142: register struct obj *otmp = o_at(u.ux, u.uy); 143: if(otmp) 144: (void) bhito(otmp, obj); 145: } 146: } else 147: (void) bhit(u.dx,u.dy,rn1(8,6),0,bhitm,bhito,obj); 148: } else { 149: switch(obj->otyp){ 150: case WAN_LIGHT: 151: litroom(TRUE); 152: break; 153: case WAN_SECRET_DOOR_DETECTION: 154: if(!findit()) return(1); 155: break; 156: case WAN_CREATE_MONSTER: 157: { register int cnt = 1; 158: if(!rn2(23)) cnt += rn2(7) + 1; 159: while(cnt--) 160: (void) makemon((struct permonst *) 0, u.ux, u.uy); 161: } 162: break; 163: case WAN_WISHING: 164: { char buf[BUFSZ]; 165: register struct obj *otmp; 166: extern struct obj *readobjnam(), *addinv(); 167: if(u.uluck + rn2(5) < 0) { 168: pline("Unfortunately, nothing happens."); 169: break; 170: } 171: pline("You may wish for an object. What do you want? "); 172: getlin(buf); 173: if(buf[0] == '\033') buf[0] = 0; 174: otmp = readobjnam(buf); 175: otmp = addinv(otmp); 176: prinv(otmp); 177: break; 178: } 179: case WAN_DIGGING: 180: /* Original effect (approximately): 181: * from CORR: dig until we pierce a wall 182: * from ROOM: piece wall and dig until we reach 183: * an ACCESSIBLE place. 184: * Currently: dig for digdepth positions; 185: * also down on request of Lennart Augustsson. 186: */ 187: { register struct rm *room; 188: register int digdepth; 189: if(u.uswallow) { 190: register struct monst *mtmp = u.ustuck; 191: 192: pline("You pierce %s's stomach wall!", 193: monnam(mtmp)); 194: mtmp->mhp = 1; /* almost dead */ 195: unstuck(mtmp); 196: mnexto(mtmp); 197: break; 198: } 199: if(u.dz) { 200: if(u.dz < 0) { 201: pline("You loosen a rock from the ceiling."); 202: pline("It falls on your head!"); 203: losehp(1, "falling rock"); 204: mksobj_at(ROCK, u.ux, u.uy); 205: fobj->quan = 1; 206: stackobj(fobj); 207: if(Invisible) newsym(u.ux, u.uy); 208: } else { 209: dighole(); 210: } 211: break; 212: } 213: zx = u.ux+u.dx; 214: zy = u.uy+u.dy; 215: digdepth = 8 + rn2(18); 216: Tmp_at(-1, '*'); /* open call */ 217: while(--digdepth >= 0) { 218: if(!isok(zx,zy)) break; 219: room = &levl[zx][zy]; 220: Tmp_at(zx,zy); 221: if(!xdnstair){ 222: if(zx < 3 || zx > COLNO-3 || 223: zy < 3 || zy > ROWNO-3) 224: break; 225: if(room->typ == HWALL || 226: room->typ == VWALL){ 227: room->typ = ROOM; 228: break; 229: } 230: } else 231: if(room->typ == HWALL || room->typ == VWALL || 232: room->typ == SDOOR || room->typ == LDOOR){ 233: room->typ = DOOR; 234: digdepth -= 2; 235: } else 236: if(room->typ == SCORR || !room->typ) { 237: room->typ = CORR; 238: digdepth--; 239: } 240: mnewsym(zx,zy); 241: zx += u.dx; 242: zy += u.dy; 243: } 244: mnewsym(zx,zy); /* not always necessary */ 245: Tmp_at(-1,-1); /* closing call */ 246: break; 247: } 248: default: 249: buzz((int) obj->otyp - WAN_MAGIC_MISSILE, 250: u.ux, u.uy, u.dx, u.dy); 251: break; 252: } 253: if(!objects[obj->otyp].oc_name_known) { 254: objects[obj->otyp].oc_name_known = 1; 255: more_experienced(0,10); 256: } 257: } 258: return(1); 259: } 260: 261: char * 262: exclam(force) 263: register 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: register char *str; 273: register struct monst *mtmp; 274: register 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: register char *str; 282: register 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: register 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: register struct monst *mtmp; 304: register struct obj *otmp; 305: register 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: register int i, ct; 344: register 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) register 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: register int type; 398: register xchar sx,sy; 399: register int dx,dy; 400: { 401: int abstype = abs(type); 402: register 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: register 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: register 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: register 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: register struct monst *mon; 545: register type; 546: { 547: register 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: register struct obj *obj; 581: { 582: register 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: register struct obj *obj; 596: { 597: register 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: register 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: register struct obj *obj, *obj2; 626: register 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: }