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