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