|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.