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