1 /* $NetBSD: monster.c,v 1.7 2001/02/05 00:57:33 christos Exp $ */ 2 3 /* 4 * monster.c Larn is copyrighted 1986 by Noah Morgan. 5 * 6 * This file contains the following functions: 7 * ---------------------------------------------------------------------------- 8 * 9 * createmonster(monstno) Function to create a monster next to the player 10 * int monstno; 11 * 12 * int cgood(x,y,itm,monst)Function to check location for emptiness 13 * int x,y,itm,monst; 14 * 15 * createitem(it,arg) Routine to place an item next to the player 16 * int it,arg; 17 * 18 * cast() Subroutine called by parse to cast a spell for the user 19 * 20 * speldamage(x) Function to perform spell functions cast by the player 21 * int x; 22 * 23 * loseint() Routine to decrement your int (intelligence) if > 3 24 * 25 * isconfuse() Routine to check to see if player is confused 26 * 27 * nospell(x,monst)Routine to return 1 if a spell doesn't affect a monster 28 * int x,monst; 29 * 30 * fullhit(xx) Function to return full damage against a monst (aka web) 31 * int xx; 32 * 33 * direct(spnum,dam,str,arg)Routine to direct spell damage 1 square in 1 dir 34 * int spnum,dam,arg; 35 * char *str; 36 * 37 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks 38 * int spnum,dam,delay; 39 * char *str,cshow; 40 * 41 * ifblind(x,y)Routine to put "monster" or the monster name into lastmosnt 42 * int x,y; 43 * 44 * tdirect(spnum) Routine to teleport away a monster 45 * int spnum; 46 * 47 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player 48 * int sp,dam; 49 * char *str; 50 * 51 * dirsub(x,y) Routine to ask for direction, then modify x,y for it 52 * int *x,*y; 53 * 54 * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds 55 * int *x,*y; 56 * 57 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst 58 * int spnum; 59 * 60 * hitmonster(x,y) Function to hit a monster at the designated coordinates 61 * int x,y; 62 * 63 * hitm(x,y,amt) Function to just hit a monster at a given coordinates 64 * int x,y,amt; 65 * 66 * hitplayer(x,y) Function for the monster to hit the player from (x,y) 67 * int x,y; 68 * 69 * dropsomething(monst) Function to create an object when a monster dies 70 * int monst; 71 * 72 * dropgold(amount) Function to drop some gold around player 73 * int amount; 74 * 75 * something(level) Function to create a random item around player 76 * int level; 77 * 78 * newobject(lev,i) Routine to return a randomly selected new object 79 * int lev,*i; 80 * 81 * spattack(atckno,xx,yy) Function to process special attacks from monsters 82 * int atckno,xx,yy; 83 * 84 * checkloss(x) Routine to subtract hp from user and flag bottomline display 85 * int x; 86 * 87 * annihilate() Routine to annihilate monsters around player, playerx,playery 88 * 89 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation 90 * int x,y,dir,lifetime; 91 * 92 * rmsphere(x,y) Function to delete a sphere of annihilation from list 93 * int x,y; 94 * 95 * sphboom(x,y) Function to perform the effects of a sphere detonation 96 * int x,y; 97 * 98 * genmonst() Function to ask for monster and genocide from game 99 * 100 */ 101 #include <sys/cdefs.h> 102 #ifndef lint 103 __RCSID("$NetBSD: monster.c,v 1.7 2001/02/05 00:57:33 christos Exp $"); 104 #endif /* not lint */ 105 106 #include <string.h> 107 #include <stdlib.h> 108 #include "header.h" 109 #include "extern.h" 110 111 struct isave { /* used for altar reality */ 112 char type; /* 0=item, 1=monster */ 113 char id; /* item number or monster number */ 114 short arg; /* the type of item or hitpoints of monster */ 115 }; 116 117 static int dirsub __P((int *, int *)); 118 /* 119 * createmonster(monstno) Function to create a monster next to the player 120 * int monstno; 121 * 122 * Enter with the monster number (1 to MAXMONST+8) 123 * Returns no value. 124 */ 125 void 126 createmonster(mon) 127 int mon; 128 { 129 int x, y, k, i; 130 if (mon < 1 || mon > MAXMONST + 8) { /* check for monster number 131 * out of bounds */ 132 beep(); 133 lprintf("\ncan't createmonst(%d)\n", (long) mon); 134 nap(3000); 135 return; 136 } 137 while (monster[mon].genocided && mon < MAXMONST) 138 mon++; /* genocided? */ 139 for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction, 140 * then try all */ 141 if (k > 8) 142 k = 1; /* wraparound the diroff arrays */ 143 x = playerx + diroffx[k]; 144 y = playery + diroffy[k]; 145 if (cgood(x, y, 0, 1)) { /* if we can create here */ 146 mitem[x][y] = mon; 147 hitp[x][y] = monster[mon].hitpoints; 148 stealth[x][y] = know[x][y] = 0; 149 switch (mon) { 150 case ROTHE: 151 case POLTERGEIST: 152 case VAMPIRE: 153 stealth[x][y] = 1; 154 }; 155 return; 156 } 157 } 158 } 159 160 /* 161 * int cgood(x,y,itm,monst) Function to check location for emptiness 162 * int x,y,itm,monst; 163 * 164 * Routine to return TRUE if a location does not have itm or monst there 165 * returns FALSE (0) otherwise 166 * Enter with itm or monst TRUE or FALSE if checking it 167 * Example: if itm==TRUE check for no item at this location 168 * if monst==TRUE check for no monster at this location 169 * This routine will return FALSE if at a wall or the dungeon exit on level 1 170 */ 171 int 172 cgood(x, y, itm, monst) 173 int x, y; 174 int itm, monst; 175 { 176 if ((y >= 0) && (y <= MAXY - 1) && (x >= 0) && (x <= MAXX - 1)) 177 /* within bounds? */ 178 if (item[x][y] != OWALL) /* can't make anything on walls */ 179 /* is it free of items? */ 180 if (itm == 0 || (item[x][y] == 0)) 181 /* is it free of monsters? */ 182 if (monst == 0 || (mitem[x][y] == 0)) 183 if ((level != 1) || (x != 33) || 184 (y != MAXY - 1)) 185 /* not exit to level 1 */ 186 return (1); 187 return (0); 188 } 189 190 /* 191 * createitem(it,arg) Routine to place an item next to the player 192 * int it,arg; 193 * 194 * Enter with the item number and its argument (iven[], ivenarg[]) 195 * Returns no value, thus we don't know about createitem() failures. 196 */ 197 void 198 createitem(it, arg) 199 int it, arg; 200 { 201 int x, y, k, i; 202 if (it >= MAXOBJ) 203 return; /* no such object */ 204 for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction, 205 * then try all */ 206 if (k > 8) 207 k = 1; /* wraparound the diroff arrays */ 208 x = playerx + diroffx[k]; 209 y = playery + diroffy[k]; 210 if (cgood(x, y, 1, 0)) { /* if we can create here */ 211 item[x][y] = it; 212 know[x][y] = 0; 213 iarg[x][y] = arg; 214 return; 215 } 216 } 217 } 218 219 /* 220 * cast() Subroutine called by parse to cast a spell for the user 221 * 222 * No arguments and no return value. 223 */ 224 static char eys[] = "\nEnter your spell: "; 225 void 226 cast() 227 { 228 int i, j, a, b, d; 229 cursors(); 230 if (c[SPELLS] <= 0) { 231 lprcat("\nYou don't have any spells!"); 232 return; 233 } 234 lprcat(eys); 235 --c[SPELLS]; 236 while ((a = lgetchar()) == 'D') { 237 seemagic(-1); 238 cursors(); 239 lprcat(eys); 240 } 241 if (a == '\33') 242 goto over; /* to escape casting a spell */ 243 if ((b = lgetchar()) == '\33') 244 goto over; /* to escape casting a spell */ 245 if ((d = lgetchar()) == '\33') { 246 over: lprcat(aborted); 247 c[SPELLS]++; 248 return; 249 } /* to escape casting a spell */ 250 #ifdef EXTRA 251 c[SPELLSCAST]++; 252 #endif 253 for (lprc('\n'), j = -1, i = 0; i < SPNUM; i++) /* seq search for his 254 * spell, hash? */ 255 if ((spelcode[i][0] == a) && (spelcode[i][1] == b) && (spelcode[i][2] == d)) 256 if (spelknow[i]) { 257 speldamage(i); 258 j = 1; 259 i = SPNUM; 260 } 261 if (j == -1) 262 lprcat(" Nothing Happened "); 263 bottomline(); 264 } 265 266 /* 267 * speldamage(x) Function to perform spell functions cast by the player 268 * int x; 269 * 270 * Enter with the spell number, returns no value. 271 * Please insure that there are 2 spaces before all messages here 272 */ 273 void 274 speldamage(x) 275 int x; 276 { 277 int i, j, clev; 278 int xl, xh, yl, yh; 279 char *p, *kn, *pm; 280 if (x >= SPNUM) 281 return; /* no such spell */ 282 if (c[TIMESTOP]) { 283 lprcat(" It didn't seem to work"); 284 return; 285 } /* not if time stopped */ 286 clev = c[LEVEL]; 287 if ((rnd(23) == 7) || (rnd(18) > c[INTELLIGENCE])) { 288 lprcat(" It didn't work!"); 289 return; 290 } 291 if (clev * 3 + 2 < x) { 292 lprcat(" Nothing happens. You seem inexperienced at this"); 293 return; 294 } 295 switch (x) { 296 /* ----- LEVEL 1 SPELLS ----- */ 297 298 case 0: 299 if (c[PROTECTIONTIME] == 0) 300 c[MOREDEFENSES] += 2; /* protection field +2 */ 301 c[PROTECTIONTIME] += 250; 302 return; 303 304 case 1: 305 i = rnd(((clev + 1) << 1)) + clev + 3; 306 godirect(x, i, (clev >= 2) ? " Your missiles hit the %s" : " Your missile hit the %s", 100, '+'); /* magic missile */ 307 308 return; 309 310 case 2: 311 if (c[DEXCOUNT] == 0) 312 c[DEXTERITY] += 3; /* dexterity */ 313 c[DEXCOUNT] += 400; 314 return; 315 316 case 3: 317 i = rnd(3) + 1; 318 p = " While the %s slept, you smashed it %d times"; 319 ws: direct(x, fullhit(i), p, i); /* sleep */ 320 return; 321 322 case 4: /* charm monster */ 323 c[CHARMCOUNT] += c[CHARISMA] << 1; 324 return; 325 326 case 5: 327 godirect(x, rnd(10) + 15 + clev, " The sound damages the %s", 70, '@'); /* sonic spear */ 328 return; 329 330 /* ----- LEVEL 2 SPELLS ----- */ 331 332 case 6: 333 i = rnd(3) + 2; 334 p = " While the %s is entangled, you hit %d times"; 335 goto ws; /* web */ 336 337 case 7: 338 if (c[STRCOUNT] == 0) 339 c[STREXTRA] += 3; /* strength */ 340 c[STRCOUNT] += 150 + rnd(100); 341 return; 342 343 case 8: 344 yl = playery - 5; /* enlightenment */ 345 yh = playery + 6; 346 xl = playerx - 15; 347 xh = playerx + 16; 348 vxy(&xl, &yl); 349 vxy(&xh, &yh); /* check bounds */ 350 for (i = yl; i <= yh; i++) /* enlightenment */ 351 for (j = xl; j <= xh; j++) 352 know[j][i] = 1; 353 draws(xl, xh + 1, yl, yh + 1); 354 return; 355 356 case 9: 357 raisehp(20 + (clev << 1)); 358 return; /* healing */ 359 360 case 10: 361 c[BLINDCOUNT] = 0; 362 return; /* cure blindness */ 363 364 case 11: 365 createmonster(makemonst(level + 1) + 8); 366 return; 367 368 case 12: 369 if (rnd(11) + 7 <= c[WISDOM]) 370 direct(x, rnd(20) + 20 + clev, " The %s believed!", 0); 371 else 372 lprcat(" It didn't believe the illusions!"); 373 return; 374 375 case 13: /* if he has the amulet of invisibility then 376 * add more time */ 377 for (j = i = 0; i < 26; i++) 378 if (iven[i] == OAMULET) 379 j += 1 + ivenarg[i]; 380 c[INVISIBILITY] += (j << 7) + 12; 381 return; 382 383 /* ----- LEVEL 3 SPELLS ----- */ 384 385 case 14: 386 godirect(x, rnd(25 + clev) + 25 + clev, " The fireball hits the %s", 40, '*'); 387 return; /* fireball */ 388 389 case 15: 390 godirect(x, rnd(25) + 20 + clev, " Your cone of cold strikes the %s", 60, 'O'); /* cold */ 391 return; 392 393 case 16: 394 dirpoly(x); 395 return; /* polymorph */ 396 397 case 17: 398 c[CANCELLATION] += 5 + clev; 399 return; /* cancellation */ 400 401 case 18: 402 c[HASTESELF] += 7 + clev; 403 return; /* haste self */ 404 405 case 19: 406 omnidirect(x, 30 + rnd(10), " The %s gasps for air"); /* cloud kill */ 407 return; 408 409 case 20: 410 xh = min(playerx + 1, MAXX - 2); 411 yh = min(playery + 1, MAXY - 2); 412 for (i = max(playerx - 1, 1); i <= xh; i++) /* vaporize rock */ 413 for (j = max(playery - 1, 1); j <= yh; j++) { 414 kn = &know[i][j]; 415 pm = &mitem[i][j]; 416 switch (*(p = &item[i][j])) { 417 case OWALL: 418 if (level < MAXLEVEL + MAXVLEVEL - 1) 419 *p = *kn = 0; 420 break; 421 422 case OSTATUE: 423 if (c[HARDGAME] < 3) { 424 *p = OBOOK; 425 iarg[i][j] = level; 426 *kn = 0; 427 } 428 break; 429 430 case OTHRONE: 431 *pm = GNOMEKING; 432 *kn = 0; 433 *p = OTHRONE2; 434 hitp[i][j] = monster[GNOMEKING].hitpoints; 435 break; 436 437 case OALTAR: 438 *pm = DEMONPRINCE; 439 *kn = 0; 440 hitp[i][j] = monster[DEMONPRINCE].hitpoints; 441 break; 442 }; 443 switch (*pm) { 444 case XORN: 445 ifblind(i, j); 446 hitm(i, j, 200); 447 break; /* Xorn takes damage from vpr */ 448 } 449 } 450 return; 451 452 /* ----- LEVEL 4 SPELLS ----- */ 453 454 case 21: 455 direct(x, 100 + clev, " The %s shrivels up", 0); /* dehydration */ 456 return; 457 458 case 22: 459 godirect(x, rnd(25) + 20 + (clev << 1), " A lightning bolt hits the %s", 1, '~'); /* lightning */ 460 return; 461 462 case 23: 463 i = min(c[HP] - 1, c[HPMAX] / 2); /* drain life */ 464 direct(x, i + i, "", 0); 465 c[HP] -= i; 466 return; 467 468 case 24: 469 if (c[GLOBE] == 0) 470 c[MOREDEFENSES] += 10; 471 c[GLOBE] += 200; 472 loseint(); /* globe of invulnerability */ 473 return; 474 475 case 25: 476 omnidirect(x, 32 + clev, " The %s struggles for air in your flood!"); /* flood */ 477 return; 478 479 case 26: 480 if (rnd(151) == 63) { 481 beep(); 482 lprcat("\nYour heart stopped!\n"); 483 nap(4000); 484 died(270); 485 return; 486 } 487 if (c[WISDOM] > rnd(10) + 10) 488 direct(x, 2000, " The %s's heart stopped", 0); /* finger of death */ 489 else 490 lprcat(" It didn't work"); 491 return; 492 493 /* ----- LEVEL 5 SPELLS ----- */ 494 495 case 27: 496 c[SCAREMONST] += rnd(10) + clev; 497 return; /* scare monster */ 498 499 case 28: 500 c[HOLDMONST] += rnd(10) + clev; 501 return; /* hold monster */ 502 503 case 29: 504 c[TIMESTOP] += rnd(20) + (clev << 1); 505 return; /* time stop */ 506 507 case 30: 508 tdirect(x); 509 return; /* teleport away */ 510 511 case 31: 512 omnidirect(x, 35 + rnd(10) + clev, " The %s cringes from the flame"); /* magic fire */ 513 return; 514 515 /* ----- LEVEL 6 SPELLS ----- */ 516 517 case 32: 518 if ((rnd(23) == 5) && (wizard == 0)) { /* sphere of 519 * annihilation */ 520 beep(); 521 lprcat("\nYou have been enveloped by the zone of nothingness!\n"); 522 nap(4000); 523 died(258); 524 return; 525 } 526 xl = playerx; 527 yl = playery; 528 loseint(); 529 i = dirsub(&xl, &yl); /* get direction of sphere */ 530 newsphere(xl, yl, i, rnd(20) + 11); /* make a sphere */ 531 return; 532 533 case 33: 534 genmonst(); 535 spelknow[33] = 0; /* genocide */ 536 loseint(); 537 return; 538 539 case 34: /* summon demon */ 540 if (rnd(100) > 30) { 541 direct(x, 150, " The demon strikes at the %s", 0); 542 return; 543 } 544 if (rnd(100) > 15) { 545 lprcat(" Nothing seems to have happened"); 546 return; 547 } 548 lprcat(" The demon turned on you and vanished!"); 549 beep(); 550 i = rnd(40) + 30; 551 lastnum = 277; 552 losehp(i); /* must say killed by a demon */ 553 return; 554 555 case 35: /* walk through walls */ 556 c[WTW] += rnd(10) + 5; 557 return; 558 559 case 36: /* alter reality */ 560 { 561 struct isave *save; /* pointer to item save 562 * structure */ 563 int sc; 564 sc = 0; /* # items saved */ 565 save = (struct isave *) malloc(sizeof(struct isave) * MAXX * MAXY * 2); 566 for (j = 0; j < MAXY; j++) 567 for (i = 0; i < MAXX; i++) { /* save all items and 568 * monsters */ 569 xl = item[i][j]; 570 if (xl && xl != OWALL && xl != OANNIHILATION) { 571 save[sc].type = 0; 572 save[sc].id = item[i][j]; 573 save[sc++].arg = iarg[i][j]; 574 } 575 if (mitem[i][j]) { 576 save[sc].type = 1; 577 save[sc].id = mitem[i][j]; 578 save[sc++].arg = hitp[i][j]; 579 } 580 item[i][j] = OWALL; 581 mitem[i][j] = 0; 582 if (wizard) 583 know[i][j] = 1; 584 else 585 know[i][j] = 0; 586 } 587 eat(1, 1); 588 if (level == 1) 589 item[33][MAXY - 1] = 0; 590 for (j = rnd(MAXY - 2), i = 1; i < MAXX - 1; i++) 591 item[i][j] = 0; 592 while (sc > 0) { /* put objects back in level */ 593 --sc; 594 if (save[sc].type == 0) { 595 int trys; 596 for (trys = 100, i = j = 1; --trys > 0 && item[i][j]; i = rnd(MAXX - 1), j = rnd(MAXY - 1)); 597 if (trys) { 598 item[i][j] = save[sc].id; 599 iarg[i][j] = save[sc].arg; 600 } 601 } else { /* put monsters back in */ 602 int trys; 603 for (trys = 100, i = j = 1; --trys > 0 && (item[i][j] == OWALL || mitem[i][j]); i = rnd(MAXX - 1), j = rnd(MAXY - 1)); 604 if (trys) { 605 mitem[i][j] = save[sc].id; 606 hitp[i][j] = save[sc].arg; 607 } 608 } 609 } 610 loseint(); 611 draws(0, MAXX, 0, MAXY); 612 if (wizard == 0) 613 spelknow[36] = 0; 614 free((char *) save); 615 positionplayer(); 616 return; 617 } 618 619 case 37: /* permanence */ 620 adjusttime(-99999L); 621 spelknow[37] = 0; /* forget */ 622 loseint(); 623 return; 624 625 default: 626 lprintf(" spell %d not available!", (long) x); 627 beep(); 628 return; 629 }; 630 } 631 632 /* 633 * loseint() Routine to subtract 1 from your int (intelligence) if > 3 634 * 635 * No arguments and no return value 636 */ 637 void 638 loseint() 639 { 640 if (--c[INTELLIGENCE] < 3) 641 c[INTELLIGENCE] = 3; 642 } 643 644 /* 645 * isconfuse() Routine to check to see if player is confused 646 * 647 * This routine prints out a message saying "You can't aim your magic!" 648 * returns 0 if not confused, non-zero (time remaining confused) if confused 649 */ 650 int 651 isconfuse() 652 { 653 if (c[CONFUSE]) { 654 lprcat(" You can't aim your magic!"); 655 beep(); 656 } 657 return (c[CONFUSE]); 658 } 659 660 /* 661 * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster 662 * int x,monst; 663 * 664 * Subroutine to return 1 if the spell can't affect the monster 665 * otherwise returns 0 666 * Enter with the spell number in x, and the monster number in monst. 667 */ 668 int 669 nospell(x, monst) 670 int x, monst; 671 { 672 int tmp; 673 if (x >= SPNUM || monst >= MAXMONST + 8 || monst < 0 || x < 0) 674 return (0); /* bad spell or monst */ 675 if ((tmp = spelweird[monst - 1][x]) == 0) 676 return (0); 677 cursors(); 678 lprc('\n'); 679 lprintf(spelmes[tmp], monster[monst].name); 680 return (1); 681 } 682 683 /* 684 * fullhit(xx) Function to return full damage against a monster (aka web) 685 * int xx; 686 * 687 * Function to return hp damage to monster due to a number of full hits 688 * Enter with the number of full hits being done 689 */ 690 int 691 fullhit(xx) 692 int xx; 693 { 694 int i; 695 if (xx < 0 || xx > 20) 696 return (0); /* fullhits are out of range */ 697 if (c[LANCEDEATH]) 698 return (10000); /* lance of death */ 699 i = xx * ((c[WCLASS] >> 1) + c[STRENGTH] + c[STREXTRA] - c[HARDGAME] - 12 + c[MOREDAM]); 700 return ((i >= 1) ? i : xx); 701 } 702 703 /* 704 * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir 705 * int spnum,dam,arg; 706 * char *str; 707 * 708 * Routine to ask for a direction to a spell and then hit the monster 709 * Enter with the spell number in spnum, the damage to be done in dam, 710 * lprintf format string in str, and lprintf's argument in arg. 711 * Returns no value. 712 */ 713 void 714 direct(spnum, dam, str, arg) 715 int spnum, dam, arg; 716 char *str; 717 { 718 int x, y; 719 int m; 720 if (spnum < 0 || spnum >= SPNUM || str == 0) 721 return; /* bad arguments */ 722 if (isconfuse()) 723 return; 724 dirsub(&x, &y); 725 m = mitem[x][y]; 726 if (item[x][y] == OMIRROR) { 727 if (spnum == 3) { /* sleep */ 728 lprcat("You fall asleep! "); 729 beep(); 730 fool: 731 arg += 2; 732 while (arg-- > 0) { 733 parse2(); 734 nap(1000); 735 } 736 return; 737 } else if (spnum == 6) { /* web */ 738 lprcat("You get stuck in your own web! "); 739 beep(); 740 goto fool; 741 } else { 742 lastnum = 278; 743 lprintf(str, "spell caster (thats you)", (long) arg); 744 beep(); 745 losehp(dam); 746 return; 747 } 748 } 749 if (m == 0) { 750 lprcat(" There wasn't anything there!"); 751 return; 752 } 753 ifblind(x, y); 754 if (nospell(spnum, m)) { 755 lasthx = x; 756 lasthy = y; 757 return; 758 } 759 lprintf(str, lastmonst, (long) arg); 760 hitm(x, y, dam); 761 } 762 763 /* 764 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks 765 * int spnum,dam,delay; 766 * char *str,cshow; 767 * 768 * Function to hit in a direction from a missile weapon and have it keep 769 * on going in that direction until its power is exhausted 770 * Enter with the spell number in spnum, the power of the weapon in hp, 771 * lprintf format string in str, the # of milliseconds to delay between 772 * locations in delay, and the character to represent the weapon in cshow. 773 * Returns no value. 774 */ 775 void 776 godirect(spnum, dam, str, delay, cshow) 777 int spnum, dam, delay; 778 char *str, cshow; 779 { 780 char *p; 781 int x, y, m; 782 int dx, dy; 783 if (spnum < 0 || spnum >= SPNUM || str == 0 || delay < 0) 784 return; /* bad args */ 785 if (isconfuse()) 786 return; 787 dirsub(&dx, &dy); 788 x = dx; 789 y = dy; 790 dx = x - playerx; 791 dy = y - playery; 792 x = playerx; 793 y = playery; 794 while (dam > 0) { 795 x += dx; 796 y += dy; 797 if ((x > MAXX - 1) || (y > MAXY - 1) || (x < 0) || (y < 0)) { 798 dam = 0; 799 break; /* out of bounds */ 800 } 801 if ((x == playerx) && (y == playery)) { /* if energy hits player */ 802 cursors(); 803 lprcat("\nYou are hit my your own magic!"); 804 beep(); 805 lastnum = 278; 806 losehp(dam); 807 return; 808 } 809 if (c[BLINDCOUNT] == 0) { /* if not blind show effect */ 810 cursor(x + 1, y + 1); 811 lprc(cshow); 812 nap(delay); 813 show1cell(x, y); 814 } 815 if ((m = mitem[x][y])) { /* is there a monster there? */ 816 ifblind(x, y); 817 if (nospell(spnum, m)) { 818 lasthx = x; 819 lasthy = y; 820 return; 821 } 822 cursors(); 823 lprc('\n'); 824 lprintf(str, lastmonst); 825 dam -= hitm(x, y, dam); 826 show1cell(x, y); 827 nap(1000); 828 x -= dx; 829 y -= dy; 830 } else 831 switch (*(p = &item[x][y])) { 832 case OWALL: 833 cursors(); 834 lprc('\n'); 835 lprintf(str, "wall"); 836 if (dam >= 50 + c[HARDGAME]) /* enough damage? */ 837 if (level < MAXLEVEL + MAXVLEVEL - 1) /* not on V3 */ 838 if ((x < MAXX - 1) && (y < MAXY - 1) && (x) && (y)) { 839 lprcat(" The wall crumbles"); 840 god3: *p = 0; 841 god: know[x][y] = 0; 842 show1cell(x, y); 843 } 844 god2: dam = 0; 845 break; 846 847 case OCLOSEDDOOR: 848 cursors(); 849 lprc('\n'); 850 lprintf(str, "door"); 851 if (dam >= 40) { 852 lprcat(" The door is blasted apart"); 853 goto god3; 854 } 855 goto god2; 856 857 case OSTATUE: 858 cursors(); 859 lprc('\n'); 860 lprintf(str, "statue"); 861 if (c[HARDGAME] < 3) 862 if (dam > 44) { 863 lprcat(" The statue crumbles"); 864 *p = OBOOK; 865 iarg[x][y] = level; 866 goto god; 867 } 868 goto god2; 869 870 case OTHRONE: 871 cursors(); 872 lprc('\n'); 873 lprintf(str, "throne"); 874 if (dam > 39) { 875 mitem[x][y] = GNOMEKING; 876 hitp[x][y] = monster[GNOMEKING].hitpoints; 877 *p = OTHRONE2; 878 goto god; 879 } 880 goto god2; 881 882 case OMIRROR: 883 dx *= -1; 884 dy *= -1; 885 break; 886 }; 887 dam -= 3 + (c[HARDGAME] >> 1); 888 } 889 } 890 891 /* 892 * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt 893 * int x,y; 894 * 895 * Subroutine to copy the word "monster" into lastmonst if the player is blind 896 * Enter with the coordinates (x,y) of the monster 897 * Returns no value. 898 */ 899 void 900 ifblind(x, y) 901 int x, y; 902 { 903 char *p; 904 vxy(&x, &y); /* verify correct x,y coordinates */ 905 if (c[BLINDCOUNT]) { 906 lastnum = 279; 907 p = "monster"; 908 } else { 909 lastnum = mitem[x][y]; 910 p = monster[lastnum].name; 911 } 912 strcpy(lastmonst, p); 913 } 914 915 /* 916 * tdirect(spnum) Routine to teleport away a monster 917 * int spnum; 918 * 919 * Routine to ask for a direction to a spell and then teleport away monster 920 * Enter with the spell number that wants to teleport away 921 * Returns no value. 922 */ 923 void 924 tdirect(spnum) 925 int spnum; 926 { 927 int x, y; 928 int m; 929 if (spnum < 0 || spnum >= SPNUM) 930 return; /* bad args */ 931 if (isconfuse()) 932 return; 933 dirsub(&x, &y); 934 if ((m = mitem[x][y]) == 0) { 935 lprcat(" There wasn't anything there!"); 936 return; 937 } 938 ifblind(x, y); 939 if (nospell(spnum, m)) { 940 lasthx = x; 941 lasthy = y; 942 return; 943 } 944 fillmonst(m); 945 mitem[x][y] = know[x][y] = 0; 946 } 947 948 /* 949 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player 950 * int sp,dam; 951 * char *str; 952 * 953 * Routine to cast a spell and then hit the monster in all directions 954 * Enter with the spell number in sp, the damage done to wach square in dam, 955 * and the lprintf string to identify the spell in str. 956 * Returns no value. 957 */ 958 void 959 omnidirect(spnum, dam, str) 960 int spnum, dam; 961 char *str; 962 { 963 int x, y, m; 964 if (spnum < 0 || spnum >= SPNUM || str == 0) 965 return; /* bad args */ 966 for (x = playerx - 1; x < playerx + 2; x++) 967 for (y = playery - 1; y < playery + 2; y++) { 968 if ((m = mitem[x][y]) != 0) { 969 if (nospell(spnum, m) == 0) { 970 ifblind(x, y); 971 cursors(); 972 lprc('\n'); 973 lprintf(str, lastmonst); 974 hitm(x, y, dam); 975 nap(800); 976 } else { 977 lasthx = x; 978 lasthy = y; 979 } 980 } 981 } 982 } 983 984 /* 985 * static dirsub(x,y) Routine to ask for direction, then modify x,y for it 986 * int *x,*y; 987 * 988 * Function to ask for a direction and modify an x,y for that direction 989 * Enter with the origination coordinates in (x,y). 990 * Returns index into diroffx[] (0-8). 991 */ 992 static int 993 dirsub(x, y) 994 int *x, *y; 995 { 996 int i; 997 lprcat("\nIn What Direction? "); 998 for (i = 0;;) 999 switch (lgetchar()) { 1000 case 'b': 1001 i++; 1002 case 'n': 1003 i++; 1004 case 'y': 1005 i++; 1006 case 'u': 1007 i++; 1008 case 'h': 1009 i++; 1010 case 'k': 1011 i++; 1012 case 'l': 1013 i++; 1014 case 'j': 1015 i++; 1016 goto out; 1017 }; 1018 out: 1019 *x = playerx + diroffx[i]; 1020 *y = playery + diroffy[i]; 1021 vxy(x, y); 1022 return (i); 1023 } 1024 1025 /* 1026 * vxy(x,y) Routine to verify/fix coordinates for being within bounds 1027 * int *x,*y; 1028 * 1029 * Function to verify x & y are within the bounds for a level 1030 * If *x or *y is not within the absolute bounds for a level, fix them so that 1031 * they are on the level. 1032 * Returns TRUE if it was out of bounds, and the *x & *y in the calling 1033 * routine are affected. 1034 */ 1035 int 1036 vxy(x, y) 1037 int *x, *y; 1038 { 1039 int flag = 0; 1040 if (*x < 0) { 1041 *x = 0; 1042 flag++; 1043 } 1044 if (*y < 0) { 1045 *y = 0; 1046 flag++; 1047 } 1048 if (*x >= MAXX) { 1049 *x = MAXX - 1; 1050 flag++; 1051 } 1052 if (*y >= MAXY) { 1053 *y = MAXY - 1; 1054 flag++; 1055 } 1056 return (flag); 1057 } 1058 1059 /* 1060 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst 1061 * int spnum; 1062 * 1063 * Subroutine to polymorph a monster and ask for the direction its in 1064 * Enter with the spell number in spmun. 1065 * Returns no value. 1066 */ 1067 void 1068 dirpoly(spnum) 1069 int spnum; 1070 { 1071 int x, y, m; 1072 if (spnum < 0 || spnum >= SPNUM) 1073 return; /* bad args */ 1074 if (isconfuse()) 1075 return; /* if he is confused, he can't aim his magic */ 1076 dirsub(&x, &y); 1077 if (mitem[x][y] == 0) { 1078 lprcat(" There wasn't anything there!"); 1079 return; 1080 } 1081 ifblind(x, y); 1082 if (nospell(spnum, mitem[x][y])) { 1083 lasthx = x; 1084 lasthy = y; 1085 return; 1086 } 1087 while (monster[m = mitem[x][y] = rnd(MAXMONST + 7)].genocided); 1088 hitp[x][y] = monster[m].hitpoints; 1089 show1cell(x, y); /* show the new monster */ 1090 } 1091 1092 /* 1093 * hitmonster(x,y) Function to hit a monster at the designated coordinates 1094 * int x,y; 1095 * 1096 * This routine is used for a bash & slash type attack on a monster 1097 * Enter with the coordinates of the monster in (x,y). 1098 * Returns no value. 1099 */ 1100 void 1101 hitmonster(x, y) 1102 int x, y; 1103 { 1104 int tmp, monst, damag = 0, flag; 1105 if (c[TIMESTOP]) 1106 return; /* not if time stopped */ 1107 vxy(&x, &y); /* verify coordinates are within range */ 1108 if ((monst = mitem[x][y]) == 0) 1109 return; 1110 hit3flag = 1; 1111 ifblind(x, y); 1112 tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + 1113 c[WCLASS] / 4 - 12; 1114 cursors(); 1115 /* need at least random chance to hit */ 1116 if ((rnd(20) < tmp - c[HARDGAME]) || (rnd(71) < 5)) { 1117 lprcat("\nYou hit"); 1118 flag = 1; 1119 damag = fullhit(1); 1120 if (damag < 9999) 1121 damag = rnd(damag) + 1; 1122 } else { 1123 lprcat("\nYou missed"); 1124 flag = 0; 1125 } 1126 lprcat(" the "); 1127 lprcat(lastmonst); 1128 if (flag) /* if the monster was hit */ 1129 if ((monst == RUSTMONSTER) || (monst == DISENCHANTRESS) || (monst == CUBE)) 1130 if (c[WIELD] > 0) 1131 if (ivenarg[c[WIELD]] > -10) { 1132 lprintf("\nYour weapon is dulled by the %s", lastmonst); 1133 beep(); 1134 --ivenarg[c[WIELD]]; 1135 } 1136 if (flag) 1137 hitm(x, y, damag); 1138 if (monst == VAMPIRE) 1139 if (hitp[x][y] < 25) { 1140 mitem[x][y] = BAT; 1141 know[x][y] = 0; 1142 } 1143 } 1144 1145 /* 1146 * hitm(x,y,amt) Function to just hit a monster at a given coordinates 1147 * int x,y,amt; 1148 * 1149 * Returns the number of hitpoints the monster absorbed 1150 * This routine is used to specifically damage a monster at a location (x,y) 1151 * Called by hitmonster(x,y) 1152 */ 1153 int 1154 hitm(x, y, amt) 1155 int x, y; 1156 int amt; 1157 { 1158 int monst; 1159 int hpoints, amt2; 1160 vxy(&x, &y); /* verify coordinates are within range */ 1161 amt2 = amt; /* save initial damage so we can return it */ 1162 monst = mitem[x][y]; 1163 if (c[HALFDAM]) 1164 amt >>= 1; /* if half damage curse adjust damage points */ 1165 if (amt <= 0) 1166 amt2 = amt = 1; 1167 lasthx = x; 1168 lasthy = y; 1169 stealth[x][y] = 1; /* make sure hitting monst breaks stealth 1170 * condition */ 1171 c[HOLDMONST] = 0; /* hit a monster breaks hold monster spell */ 1172 switch (monst) { /* if a dragon and orb(s) of dragon slaying */ 1173 case WHITEDRAGON: 1174 case REDDRAGON: 1175 case GREENDRAGON: 1176 case BRONZEDRAGON: 1177 case PLATINUMDRAGON: 1178 case SILVERDRAGON: 1179 amt *= 1 + (c[SLAYING] << 1); 1180 break; 1181 } 1182 /* invincible monster fix is here */ 1183 if (hitp[x][y] > monster[monst].hitpoints) 1184 hitp[x][y] = monster[monst].hitpoints; 1185 if ((hpoints = hitp[x][y]) <= amt) { 1186 #ifdef EXTRA 1187 c[MONSTKILLED]++; 1188 #endif 1189 lprintf("\nThe %s died!", lastmonst); 1190 raiseexperience((long) monster[monst].experience); 1191 amt = monster[monst].gold; 1192 if (amt > 0) 1193 dropgold(rnd(amt) + amt); 1194 dropsomething(monst); 1195 disappear(x, y); 1196 bottomline(); 1197 return (hpoints); 1198 } 1199 hitp[x][y] = hpoints - amt; 1200 return (amt2); 1201 } 1202 1203 /* 1204 * hitplayer(x,y) Function for the monster to hit the player from (x,y) 1205 * int x,y; 1206 * 1207 * Function for the monster to hit the player with monster at location x,y 1208 * Returns nothing of value. 1209 */ 1210 void 1211 hitplayer(x, y) 1212 int x, y; 1213 { 1214 int dam, tmp, mster, bias; 1215 vxy(&x, &y); /* verify coordinates are within range */ 1216 lastnum = mster = mitem[x][y]; 1217 /* 1218 * spirit naga's and poltergeist's do nothing if scarab of negate 1219 * spirit 1220 */ 1221 if (c[NEGATESPIRIT] || c[SPIRITPRO]) 1222 if ((mster == POLTERGEIST) || (mster == SPIRITNAGA)) 1223 return; 1224 /* if undead and cube of undead control */ 1225 if (c[CUBEofUNDEAD] || c[UNDEADPRO]) 1226 if ((mster == VAMPIRE) || (mster == WRAITH) || (mster == ZOMBIE)) 1227 return; 1228 if ((know[x][y] & 1) == 0) { 1229 know[x][y] = 1; 1230 show1cell(x, y); 1231 } 1232 bias = (c[HARDGAME]) + 1; 1233 hitflag = hit2flag = hit3flag = 1; 1234 yrepcount = 0; 1235 cursors(); 1236 ifblind(x, y); 1237 if (c[INVISIBILITY]) 1238 if (rnd(33) < 20) { 1239 lprintf("\nThe %s misses wildly", lastmonst); 1240 return; 1241 } 1242 if (c[CHARMCOUNT]) 1243 if (rnd(30) + 5 * monster[mster].level - c[CHARISMA] < 30) { 1244 lprintf("\nThe %s is awestruck at your magnificence!", lastmonst); 1245 return; 1246 } 1247 if (mster == BAT) 1248 dam = 1; 1249 else { 1250 dam = monster[mster].damage; 1251 dam += rnd((int) ((dam < 1) ? 1 : dam)) + monster[mster].level; 1252 } 1253 tmp = 0; 1254 if (monster[mster].attack > 0) 1255 if (((dam + bias + 8) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) { 1256 if (spattack(monster[mster].attack, x, y)) { 1257 flushall(); 1258 return; 1259 } 1260 tmp = 1; 1261 bias -= 2; 1262 cursors(); 1263 } 1264 if (((dam + bias) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) { 1265 lprintf("\n The %s hit you ", lastmonst); 1266 tmp = 1; 1267 if ((dam -= c[AC]) < 0) 1268 dam = 0; 1269 if (dam > 0) { 1270 losehp(dam); 1271 bottomhp(); 1272 flushall(); 1273 } 1274 } 1275 if (tmp == 0) 1276 lprintf("\n The %s missed ", lastmonst); 1277 } 1278 1279 /* 1280 * dropsomething(monst) Function to create an object when a monster dies 1281 * int monst; 1282 * 1283 * Function to create an object near the player when certain monsters are killed 1284 * Enter with the monster number 1285 * Returns nothing of value. 1286 */ 1287 void 1288 dropsomething(monst) 1289 int monst; 1290 { 1291 switch (monst) { 1292 case ORC: 1293 case NYMPH: 1294 case ELF: 1295 case TROGLODYTE: 1296 case TROLL: 1297 case ROTHE: 1298 case VIOLETFUNGI: 1299 case PLATINUMDRAGON: 1300 case GNOMEKING: 1301 case REDDRAGON: 1302 something(level); 1303 return; 1304 1305 case LEPRECHAUN: 1306 if (rnd(101) >= 75) 1307 creategem(); 1308 if (rnd(5) == 1) 1309 dropsomething(LEPRECHAUN); 1310 return; 1311 } 1312 } 1313 1314 /* 1315 * dropgold(amount) Function to drop some gold around player 1316 * int amount; 1317 * 1318 * Enter with the number of gold pieces to drop 1319 * Returns nothing of value. 1320 */ 1321 void 1322 dropgold(amount) 1323 int amount; 1324 { 1325 if (amount > 250) 1326 createitem(OMAXGOLD, amount / 100); 1327 else 1328 createitem(OGOLDPILE, amount); 1329 } 1330 1331 /* 1332 * something(level) Function to create a random item around player 1333 * int level; 1334 * 1335 * Function to create an item from a designed probability around player 1336 * Enter with the cave level on which something is to be dropped 1337 * Returns nothing of value. 1338 */ 1339 void 1340 something(level) 1341 int level; 1342 { 1343 int j; 1344 int i; 1345 if (level < 0 || level > MAXLEVEL + MAXVLEVEL) 1346 return; /* correct level? */ 1347 if (rnd(101) < 8) 1348 something(level); /* possibly more than one item */ 1349 j = newobject(level, &i); 1350 createitem(j, i); 1351 } 1352 1353 /* 1354 * newobject(lev,i) Routine to return a randomly selected new object 1355 * int lev,*i; 1356 * 1357 * Routine to return a randomly selected object to be created 1358 * Returns the object number created, and sets *i for its argument 1359 * Enter with the cave level and a pointer to the items arg 1360 */ 1361 static char nobjtab[] = { 1362 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION, OPOTION, 1363 OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE, 1364 OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, 1365 OLEATHER, OLEATHER, OLEATHER, OREGENRING, OPROTRING, 1366 OENERGYRING, ODEXRING, OSTRRING, OSPEAR, OBELT, ORING, 1367 OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE, 1368 OLONGSWORD}; 1369 1370 int 1371 newobject(lev, i) 1372 int lev, *i; 1373 { 1374 int tmp = 32, j; 1375 if (level < 0 || level > MAXLEVEL + MAXVLEVEL) 1376 return (0); /* correct level? */ 1377 if (lev > 6) 1378 tmp = 37; 1379 else if (lev > 4) 1380 tmp = 35; 1381 j = nobjtab[tmp = rnd(tmp)]; /* the object type */ 1382 switch (tmp) { 1383 case 1: 1384 case 2: 1385 case 3: 1386 case 4: 1387 *i = newscroll(); 1388 break; 1389 case 5: 1390 case 6: 1391 case 7: 1392 case 8: 1393 *i = newpotion(); 1394 break; 1395 case 9: 1396 case 10: 1397 case 11: 1398 case 12: 1399 *i = rnd((lev + 1) * 10) + lev * 10 + 10; 1400 break; 1401 case 13: 1402 case 14: 1403 case 15: 1404 case 16: 1405 *i = lev; 1406 break; 1407 case 17: 1408 case 18: 1409 case 19: 1410 if (!(*i = newdagger())) 1411 return (0); 1412 break; 1413 case 20: 1414 case 21: 1415 case 22: 1416 if (!(*i = newleather())) 1417 return (0); 1418 break; 1419 case 23: 1420 case 32: 1421 case 35: 1422 *i = rund(lev / 3 + 1); 1423 break; 1424 case 24: 1425 case 26: 1426 *i = rnd(lev / 4 + 1); 1427 break; 1428 case 25: 1429 *i = rund(lev / 4 + 1); 1430 break; 1431 case 27: 1432 *i = rnd(lev / 2 + 1); 1433 break; 1434 case 30: 1435 case 33: 1436 *i = rund(lev / 2 + 1); 1437 break; 1438 case 28: 1439 *i = rund(lev / 3 + 1); 1440 if (*i == 0) 1441 return (0); 1442 break; 1443 case 29: 1444 case 31: 1445 *i = rund(lev / 2 + 1); 1446 if (*i == 0) 1447 return (0); 1448 break; 1449 case 34: 1450 *i = newchain(); 1451 break; 1452 case 36: 1453 *i = newplate(); 1454 break; 1455 case 37: 1456 *i = newsword(); 1457 break; 1458 } 1459 return (j); 1460 } 1461 1462 /* 1463 * spattack(atckno,xx,yy) Function to process special attacks from monsters 1464 * int atckno,xx,yy; 1465 * 1466 * Enter with the special attack number, and the coordinates (xx,yy) 1467 * of the monster that is special attacking 1468 * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise 1469 * 1470 * atckno monster effect 1471 * --------------------------------------------------- 1472 * 0 none 1473 * 1 rust monster eat armor 1474 * 2 hell hound breathe light fire 1475 * 3 dragon breathe fire 1476 * 4 giant centipede weakening sing 1477 * 5 white dragon cold breath 1478 * 6 wraith drain level 1479 * 7 waterlord water gusher 1480 * 8 leprechaun steal gold 1481 * 9 disenchantress disenchant weapon or armor 1482 * 10 ice lizard hits with barbed tail 1483 * 11 umber hulk confusion 1484 * 12 spirit naga cast spells taken from special attacks 1485 * 13 platinum dragon psionics 1486 * 14 nymph steal objects 1487 * 15 bugbear bite 1488 * 16 osequip bite 1489 * 1490 * char rustarm[ARMORTYPES][2]; 1491 * special array for maximum rust damage to armor from rustmonster 1492 * format is: { armor type , minimum attribute 1493 */ 1494 #define ARMORTYPES 6 1495 static char rustarm[ARMORTYPES][2] = { 1496 { OSTUDLEATHER, -2 }, 1497 { ORING, -4 }, 1498 { OCHAIN, -5 }, 1499 { OSPLINT, -6 }, 1500 { OPLATE, -8 }, 1501 { OPLATEARMOR, -9} 1502 }; 1503 static char spsel[] = {1, 2, 3, 5, 6, 8, 9, 11, 13, 14}; 1504 int 1505 spattack(x, xx, yy) 1506 int x, xx, yy; 1507 { 1508 int i, j = 0, k, m; 1509 char *p = 0; 1510 if (c[CANCELLATION]) 1511 return (0); 1512 vxy(&xx, &yy); /* verify x & y coordinates */ 1513 switch (x) { 1514 case 1: /* rust your armor, j=1 when rusting has occurred */ 1515 m = k = c[WEAR]; 1516 if ((i = c[SHIELD]) != -1) { 1517 if (--ivenarg[i] < -1) 1518 ivenarg[i] = -1; 1519 else 1520 j = 1; 1521 } 1522 if ((j == 0) && (k != -1)) { 1523 m = iven[k]; 1524 for (i = 0; i < ARMORTYPES; i++) 1525 /* find his armor in table */ 1526 if (m == rustarm[i][0]) { 1527 if (--ivenarg[k] < rustarm[i][1]) 1528 ivenarg[k] = rustarm[i][1]; 1529 else 1530 j = 1; 1531 break; 1532 } 1533 } 1534 if (j == 0) /* if rusting did not occur */ 1535 switch (m) { 1536 case OLEATHER: 1537 p = "\nThe %s hit you -- Your lucky you have leather on"; 1538 break; 1539 case OSSPLATE: 1540 p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!"; 1541 break; 1542 } 1543 else { 1544 beep(); 1545 p = "\nThe %s hit you -- your armor feels weaker"; 1546 } 1547 break; 1548 1549 case 2: 1550 i = rnd(15) + 8 - c[AC]; 1551 spout: p = "\nThe %s breathes fire at you!"; 1552 if (c[FIRERESISTANCE]) 1553 p = "\nThe %s's flame doesn't phase you!"; 1554 else 1555 spout2: if (p) { 1556 lprintf(p, lastmonst); 1557 beep(); 1558 } 1559 checkloss(i); 1560 return (0); 1561 1562 case 3: 1563 i = rnd(20) + 25 - c[AC]; 1564 goto spout; 1565 1566 case 4: 1567 if (c[STRENGTH] > 3) { 1568 p = "\nThe %s stung you! You feel weaker"; 1569 beep(); 1570 --c[STRENGTH]; 1571 } else 1572 p = "\nThe %s stung you!"; 1573 break; 1574 1575 case 5: 1576 p = "\nThe %s blasts you with his cold breath"; 1577 i = rnd(15) + 18 - c[AC]; 1578 goto spout2; 1579 1580 case 6: 1581 lprintf("\nThe %s drains you of your life energy!", lastmonst); 1582 loselevel(); 1583 beep(); 1584 return (0); 1585 1586 case 7: 1587 p = "\nThe %s got you with a gusher!"; 1588 i = rnd(15) + 25 - c[AC]; 1589 goto spout2; 1590 1591 case 8: 1592 if (c[NOTHEFT]) 1593 return (0); /* he has a device of no theft */ 1594 if (c[GOLD]) { 1595 p = "\nThe %s hit you -- Your purse feels lighter"; 1596 if (c[GOLD] > 32767) 1597 c[GOLD] >>= 1; 1598 else 1599 c[GOLD] -= rnd((int) (1 + (c[GOLD] >> 1))); 1600 if (c[GOLD] < 0) 1601 c[GOLD] = 0; 1602 } else 1603 p = "\nThe %s couldn't find any gold to steal"; 1604 lprintf(p, lastmonst); 1605 disappear(xx, yy); 1606 beep(); 1607 bottomgold(); 1608 return (1); 1609 1610 case 9: 1611 for (j = 50;;) {/* disenchant */ 1612 i = rund(26); 1613 m = iven[i]; /* randomly select item */ 1614 if (m > 0 && ivenarg[i] > 0 && m != OSCROLL && m != OPOTION) { 1615 if ((ivenarg[i] -= 3) < 0) 1616 ivenarg[i] = 0; 1617 lprintf("\nThe %s hits you -- you feel a sense of loss", lastmonst); 1618 srcount = 0; 1619 beep(); 1620 show3(i); 1621 bottomline(); 1622 return (0); 1623 } 1624 if (--j <= 0) { 1625 p = "\nThe %s nearly misses"; 1626 break; 1627 } 1628 break; 1629 } 1630 break; 1631 1632 case 10: 1633 p = "\nThe %s hit you with his barbed tail"; 1634 i = rnd(25) - c[AC]; 1635 goto spout2; 1636 1637 case 11: 1638 p = "\nThe %s has confused you"; 1639 beep(); 1640 c[CONFUSE] += 10 + rnd(10); 1641 break; 1642 1643 case 12: /* performs any number of other special 1644 * attacks */ 1645 return (spattack(spsel[rund(10)], xx, yy)); 1646 1647 case 13: 1648 p = "\nThe %s flattens you with his psionics!"; 1649 i = rnd(15) + 30 - c[AC]; 1650 goto spout2; 1651 1652 case 14: 1653 if (c[NOTHEFT]) 1654 return (0); /* he has device of no theft */ 1655 if (emptyhanded() == 1) { 1656 p = "\nThe %s couldn't find anything to steal"; 1657 break; 1658 } 1659 lprintf("\nThe %s picks your pocket and takes:", lastmonst); 1660 beep(); 1661 if (stealsomething() == 0) 1662 lprcat(" nothing"); 1663 disappear(xx, yy); 1664 bottomline(); 1665 return (1); 1666 1667 case 15: 1668 i = rnd(10) + 5 - c[AC]; 1669 spout3: p = "\nThe %s bit you!"; 1670 goto spout2; 1671 1672 case 16: 1673 i = rnd(15) + 10 - c[AC]; 1674 goto spout3; 1675 }; 1676 if (p) { 1677 lprintf(p, lastmonst); 1678 bottomline(); 1679 } 1680 return (0); 1681 } 1682 1683 /* 1684 * checkloss(x) Routine to subtract hp from user and flag bottomline display 1685 * int x; 1686 * 1687 * Routine to subtract hitpoints from the user and flag the bottomline display 1688 * Enter with the number of hit points to lose 1689 * Note: if x > c[HP] this routine could kill the player! 1690 */ 1691 void 1692 checkloss(x) 1693 int x; 1694 { 1695 if (x > 0) { 1696 losehp(x); 1697 bottomhp(); 1698 } 1699 } 1700 1701 /* 1702 * annihilate() Routine to annihilate all monsters around player (playerx,playery) 1703 * 1704 * Gives player experience, but no dropped objects 1705 * Returns the experience gained from all monsters killed 1706 */ 1707 int 1708 annihilate() 1709 { 1710 int i, j; 1711 long k; 1712 u_char *p; 1713 for (k = 0, i = playerx - 1; i <= playerx + 1; i++) 1714 for (j = playery - 1; j <= playery + 1; j++) 1715 if (!vxy(&i, &j)) { /* if not out of bounds */ 1716 if (*(p = &mitem[i][j])) { /* if a monster there */ 1717 if (*p < DEMONLORD + 2) { 1718 k += monster[*p].experience; 1719 *p = know[i][j] = 0; 1720 } else { 1721 lprintf("\nThe %s barely escapes being annihilated!", monster[*p].name); 1722 hitp[i][j] = (hitp[i][j] >> 1) + 1; /* lose half hit points */ 1723 } 1724 } 1725 } 1726 if (k > 0) { 1727 lprcat("\nYou hear loud screams of agony!"); 1728 raiseexperience((long) k); 1729 } 1730 return (k); 1731 } 1732 1733 /* 1734 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation 1735 * int x,y,dir,lifetime; 1736 * 1737 * Enter with the coordinates of the sphere in x,y 1738 * the direction (0-8 diroffx format) in dir, and the lifespan of the 1739 * sphere in lifetime (in turns) 1740 * Returns the number of spheres currently in existence 1741 */ 1742 int 1743 newsphere(x, y, dir, life) 1744 int x, y, dir, life; 1745 { 1746 int m; 1747 struct sphere *sp; 1748 if (((sp = (struct sphere *) malloc(sizeof(struct sphere)))) == 0) 1749 return (c[SPHCAST]); /* can't malloc, therefore failure */ 1750 if (dir >= 9) 1751 dir = 0; /* no movement if direction not found */ 1752 if (level == 0) 1753 vxy(&x, &y); /* don't go out of bounds */ 1754 else { 1755 if (x < 1) 1756 x = 1; 1757 if (x >= MAXX - 1) 1758 x = MAXX - 2; 1759 if (y < 1) 1760 y = 1; 1761 if (y >= MAXY - 1) 1762 y = MAXY - 2; 1763 } 1764 if ((m = mitem[x][y]) >= DEMONLORD + 4) { /* demons dispel spheres */ 1765 know[x][y] = 1; 1766 show1cell(x, y);/* show the demon (ha ha) */ 1767 cursors(); 1768 lprintf("\nThe %s dispels the sphere!", monster[m].name); 1769 beep(); 1770 rmsphere(x, y); /* remove any spheres that are here */ 1771 return (c[SPHCAST]); 1772 } 1773 if (m == DISENCHANTRESS) { /* disenchantress cancels spheres */ 1774 cursors(); 1775 lprintf("\nThe %s causes cancellation of the sphere!", monster[m].name); 1776 beep(); 1777 boom: sphboom(x, y); /* blow up stuff around sphere */ 1778 rmsphere(x, y); /* remove any spheres that are here */ 1779 return (c[SPHCAST]); 1780 } 1781 if (c[CANCELLATION]) { /* cancellation cancels spheres */ 1782 cursors(); 1783 lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); 1784 beep(); 1785 goto boom; 1786 } 1787 if (item[x][y] == OANNIHILATION) { /* collision of spheres 1788 * detonates spheres */ 1789 cursors(); 1790 lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); 1791 beep(); 1792 rmsphere(x, y); 1793 goto boom; 1794 } 1795 if (playerx == x && playery == y) { /* collision of sphere and 1796 * player! */ 1797 cursors(); 1798 lprcat("\nYou have been enveloped by the zone of nothingness!\n"); 1799 beep(); 1800 rmsphere(x, y); /* remove any spheres that are here */ 1801 nap(4000); 1802 died(258); 1803 } 1804 item[x][y] = OANNIHILATION; 1805 mitem[x][y] = 0; 1806 know[x][y] = 1; 1807 show1cell(x, y); /* show the new sphere */ 1808 sp->x = x; 1809 sp->y = y; 1810 sp->lev = level; 1811 sp->dir = dir; 1812 sp->lifetime = life; 1813 sp->p = 0; 1814 if (spheres == 0) 1815 spheres = sp; /* if first node in the sphere list */ 1816 else { /* add sphere to beginning of linked list */ 1817 sp->p = spheres; 1818 spheres = sp; 1819 } 1820 return (++c[SPHCAST]); /* one more sphere in the world */ 1821 } 1822 1823 /* 1824 * rmsphere(x,y) Function to delete a sphere of annihilation from list 1825 * int x,y; 1826 * 1827 * Enter with the coordinates of the sphere (on current level) 1828 * Returns the number of spheres currently in existence 1829 */ 1830 int 1831 rmsphere(x, y) 1832 int x, y; 1833 { 1834 struct sphere *sp, *sp2 = 0; 1835 for (sp = spheres; sp; sp2 = sp, sp = sp->p) 1836 if (level == sp->lev) /* is sphere on this level? */ 1837 if ((x == sp->x) && (y == sp->y)) { /* locate sphere at this 1838 * location */ 1839 item[x][y] = mitem[x][y] = 0; 1840 know[x][y] = 1; 1841 show1cell(x, y); /* show the now missing 1842 * sphere */ 1843 --c[SPHCAST]; 1844 if (sp == spheres) { 1845 sp2 = sp; 1846 spheres = sp->p; 1847 free((char *) sp2); 1848 } else { 1849 sp2->p = sp->p; 1850 free((char *) sp); 1851 } 1852 break; 1853 } 1854 return (c[SPHCAST]); /* return number of spheres in the world */ 1855 } 1856 1857 /* 1858 * sphboom(x,y) Function to perform the effects of a sphere detonation 1859 * int x,y; 1860 * 1861 * Enter with the coordinates of the blast, Returns no value 1862 */ 1863 void 1864 sphboom(x, y) 1865 int x, y; 1866 { 1867 int i, j; 1868 if (c[HOLDMONST]) 1869 c[HOLDMONST] = 1; 1870 if (c[CANCELLATION]) 1871 c[CANCELLATION] = 1; 1872 for (j = max(1, x - 2); j < min(x + 3, MAXX - 1); j++) 1873 for (i = max(1, y - 2); i < min(y + 3, MAXY - 1); i++) { 1874 item[j][i] = mitem[j][i] = 0; 1875 show1cell(j, i); 1876 if (playerx == j && playery == i) { 1877 cursors(); 1878 beep(); 1879 lprcat("\nYou were too close to the sphere!"); 1880 nap(3000); 1881 died(283); /* player killed in explosion */ 1882 } 1883 } 1884 } 1885 1886 /* 1887 * genmonst() Function to ask for monster and genocide from game 1888 * 1889 * This is done by setting a flag in the monster[] structure 1890 */ 1891 void 1892 genmonst() 1893 { 1894 int i, j; 1895 cursors(); 1896 lprcat("\nGenocide what monster? "); 1897 for (i = 0; (!isalpha(i)) && (i != ' '); i = lgetchar()); 1898 lprc(i); 1899 for (j = 0; j < MAXMONST; j++) /* search for the monster type */ 1900 if (monstnamelist[j] == i) { /* have we found it? */ 1901 monster[j].genocided = 1; /* genocided from game */ 1902 lprintf(" There will be no more %s's", monster[j].name); 1903 /* now wipe out monsters on this level */ 1904 newcavelevel(level); 1905 draws(0, MAXX, 0, MAXY); 1906 bot_linex(); 1907 return; 1908 } 1909 lprcat(" You sense failure!"); 1910 } 1911