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