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