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