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