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