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