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