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