monster.c revision 1.13 1 /* $NetBSD: monster.c,v 1.13 2008/01/28 05:38:54 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.13 2008/01/28 05:38:54 dholland 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(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(%ld)\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(int x, int y, int theitem, int monst)
173 {
174 #define itm __lose
175 if ((y >= 0) && (y <= MAXY - 1) && (x >= 0) && (x <= MAXX - 1))
176 /* within bounds? */
177 if (item[x][y] != OWALL) /* can't make anything on walls */
178 /* is it free of items? */
179 if (theitem == 0 || (item[x][y] == 0))
180 /* is it free of monsters? */
181 if (monst == 0 || (mitem[x][y] == 0))
182 if ((level != 1) || (x != 33) ||
183 (y != MAXY - 1))
184 /* not exit to level 1 */
185 return (1);
186 return (0);
187 }
188
189 /*
190 * createitem(it,arg) Routine to place an item next to the player
191 * int it,arg;
192 *
193 * Enter with the item number and its argument (iven[], ivenarg[])
194 * Returns no value, thus we don't know about createitem() failures.
195 */
196 void
197 createitem(it, arg)
198 int it, arg;
199 {
200 int x, y, k, i;
201 if (it >= MAXOBJ)
202 return; /* no such object */
203 for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction,
204 * then try all */
205 if (k > 8)
206 k = 1; /* wraparound the diroff arrays */
207 x = playerx + diroffx[k];
208 y = playery + diroffy[k];
209 if (cgood(x, y, 1, 0)) { /* if we can create here */
210 item[x][y] = it;
211 know[x][y] = 0;
212 iarg[x][y] = arg;
213 return;
214 }
215 }
216 }
217
218 /*
219 * cast() Subroutine called by parse to cast a spell for the user
220 *
221 * No arguments and no return value.
222 */
223 static char eys[] = "\nEnter your spell: ";
224 void
225 cast()
226 {
227 int i, j, a, b, d;
228 cursors();
229 if (c[SPELLS] <= 0) {
230 lprcat("\nYou don't have any spells!");
231 return;
232 }
233 lprcat(eys);
234 --c[SPELLS];
235 while ((a = lgetchar()) == 'D') {
236 seemagic(-1);
237 cursors();
238 lprcat(eys);
239 }
240 if (a == '\33')
241 goto over; /* to escape casting a spell */
242 if ((b = lgetchar()) == '\33')
243 goto over; /* to escape casting a spell */
244 if ((d = lgetchar()) == '\33') {
245 over: lprcat(aborted);
246 c[SPELLS]++;
247 return;
248 } /* to escape casting a spell */
249 #ifdef EXTRA
250 c[SPELLSCAST]++;
251 #endif
252 for (lprc('\n'), j = -1, i = 0; i < SPNUM; i++) /* seq search for his
253 * spell, hash? */
254 if ((spelcode[i][0] == a) && (spelcode[i][1] == b) && (spelcode[i][2] == d))
255 if (spelknow[i]) {
256 speldamage(i);
257 j = 1;
258 i = SPNUM;
259 }
260 if (j == -1)
261 lprcat(" Nothing Happened ");
262 bottomline();
263 }
264
265 /*
266 * speldamage(x) Function to perform spell functions cast by the player
267 * int x;
268 *
269 * Enter with the spell number, returns no value.
270 * Please insure that there are 2 spaces before all messages here
271 */
272 void
273 speldamage(int x)
274 {
275 int i, j, clev;
276 int xl, xh, yl, yh;
277 u_char *p, *kn, *pm;
278
279 if (x >= SPNUM)
280 return; /* no such spell */
281 if (c[TIMESTOP]) {
282 lprcat(" It didn't seem to work");
283 return;
284 } /* not if time stopped */
285 clev = c[LEVEL];
286 if ((rnd(23) == 7) || (rnd(18) > c[INTELLIGENCE])) {
287 lprcat(" It didn't work!");
288 return;
289 }
290 if (clev * 3 + 2 < x) {
291 lprcat(" Nothing happens. You seem inexperienced at this");
292 return;
293 }
294 switch (x) {
295 /* ----- LEVEL 1 SPELLS ----- */
296
297 case 0:
298 if (c[PROTECTIONTIME] == 0)
299 c[MOREDEFENSES] += 2; /* protection field +2 */
300 c[PROTECTIONTIME] += 250;
301 return;
302
303 case 1:
304 i = rnd(((clev + 1) << 1)) + clev + 3;
305 godirect(x, i, (clev >= 2) ? " Your missiles hit the %s" : " Your missile hit the %s", 100, '+'); /* magic missile */
306
307 return;
308
309 case 2:
310 if (c[DEXCOUNT] == 0)
311 c[DEXTERITY] += 3; /* dexterity */
312 c[DEXCOUNT] += 400;
313 return;
314
315 case 3: /* sleep */
316 i = rnd(3) + 1;
317 direct(x, fullhit(i),
318 " While the %s slept, you smashed it %ld times", i);
319 return;
320
321 case 4: /* charm monster */
322 c[CHARMCOUNT] += c[CHARISMA] << 1;
323 return;
324
325 case 5:
326 godirect(x, rnd(10) + 15 + clev, " The sound damages the %s", 70, '@'); /* sonic spear */
327 return;
328
329 /* ----- LEVEL 2 SPELLS ----- */
330
331 case 6: /* web */
332 i = rnd(3) + 2;
333 direct(x, fullhit(i),
334 " While the %s is entangled, you hit %ld times", i);
335 return;
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 %ld 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 const 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 (that's 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 const char *str, cshow;
779 {
780 u_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 by 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(int x, int y)
901 {
902 const char *p;
903
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(int spnum, int dam, const char *str)
960 {
961 int x, y, m;
962
963 if (spnum < 0 || spnum >= SPNUM || str == 0)
964 return; /* bad args */
965 for (x = playerx - 1; x < playerx + 2; x++)
966 for (y = playery - 1; y < playery + 2; y++) {
967 if ((m = mitem[x][y]) != 0) {
968 if (nospell(spnum, m) == 0) {
969 ifblind(x, y);
970 cursors();
971 lprc('\n');
972 lprintf(str, lastmonst);
973 hitm(x, y, dam);
974 nap(800);
975 } else {
976 lasthx = x;
977 lasthy = y;
978 }
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 (lgetchar()) {
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 nagas and poltergeists 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(int cavelevel)
1340 {
1341 int j;
1342 int i;
1343 if (cavelevel < 0 || cavelevel > MAXLEVEL + MAXVLEVEL)
1344 return; /* correct level? */
1345 if (rnd(101) < 8)
1346 something(cavelevel); /* possibly more than one item */
1347 j = newobject(cavelevel, &i);
1348 createitem(j, i);
1349 }
1350
1351 /*
1352 * newobject(lev,i) Routine to return a randomly selected new object
1353 * int lev,*i;
1354 *
1355 * Routine to return a randomly selected object to be created
1356 * Returns the object number created, and sets *i for its argument
1357 * Enter with the cave level and a pointer to the items arg
1358 */
1359 static char nobjtab[] = {
1360 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION, OPOTION,
1361 OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE,
1362 OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER,
1363 OLEATHER, OLEATHER, OLEATHER, OREGENRING, OPROTRING,
1364 OENERGYRING, ODEXRING, OSTRRING, OSPEAR, OBELT, ORING,
1365 OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
1366 OLONGSWORD};
1367
1368 int
1369 newobject(lev, i)
1370 int lev, *i;
1371 {
1372 int tmp = 32, j;
1373 if (level < 0 || level > MAXLEVEL + MAXVLEVEL)
1374 return (0); /* correct level? */
1375 if (lev > 6)
1376 tmp = 37;
1377 else if (lev > 4)
1378 tmp = 35;
1379 j = nobjtab[tmp = rnd(tmp)]; /* the object type */
1380 switch (tmp) {
1381 case 1:
1382 case 2:
1383 case 3:
1384 case 4:
1385 *i = newscroll();
1386 break;
1387 case 5:
1388 case 6:
1389 case 7:
1390 case 8:
1391 *i = newpotion();
1392 break;
1393 case 9:
1394 case 10:
1395 case 11:
1396 case 12:
1397 *i = rnd((lev + 1) * 10) + lev * 10 + 10;
1398 break;
1399 case 13:
1400 case 14:
1401 case 15:
1402 case 16:
1403 *i = lev;
1404 break;
1405 case 17:
1406 case 18:
1407 case 19:
1408 if (!(*i = newdagger()))
1409 return (0);
1410 break;
1411 case 20:
1412 case 21:
1413 case 22:
1414 if (!(*i = newleather()))
1415 return (0);
1416 break;
1417 case 23:
1418 case 32:
1419 case 35:
1420 *i = rund(lev / 3 + 1);
1421 break;
1422 case 24:
1423 case 26:
1424 *i = rnd(lev / 4 + 1);
1425 break;
1426 case 25:
1427 *i = rund(lev / 4 + 1);
1428 break;
1429 case 27:
1430 *i = rnd(lev / 2 + 1);
1431 break;
1432 case 30:
1433 case 33:
1434 *i = rund(lev / 2 + 1);
1435 break;
1436 case 28:
1437 *i = rund(lev / 3 + 1);
1438 if (*i == 0)
1439 return (0);
1440 break;
1441 case 29:
1442 case 31:
1443 *i = rund(lev / 2 + 1);
1444 if (*i == 0)
1445 return (0);
1446 break;
1447 case 34:
1448 *i = newchain();
1449 break;
1450 case 36:
1451 *i = newplate();
1452 break;
1453 case 37:
1454 *i = newsword();
1455 break;
1456 }
1457 return (j);
1458 }
1459
1460 /*
1461 * spattack(atckno,xx,yy) Function to process special attacks from monsters
1462 * int atckno,xx,yy;
1463 *
1464 * Enter with the special attack number, and the coordinates (xx,yy)
1465 * of the monster that is special attacking
1466 * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
1467 *
1468 * atckno monster effect
1469 * ---------------------------------------------------
1470 * 0 none
1471 * 1 rust monster eat armor
1472 * 2 hell hound breathe light fire
1473 * 3 dragon breathe fire
1474 * 4 giant centipede weakening sing
1475 * 5 white dragon cold breath
1476 * 6 wraith drain level
1477 * 7 waterlord water gusher
1478 * 8 leprechaun steal gold
1479 * 9 disenchantress disenchant weapon or armor
1480 * 10 ice lizard hits with barbed tail
1481 * 11 umber hulk confusion
1482 * 12 spirit naga cast spells taken from special attacks
1483 * 13 platinum dragon psionics
1484 * 14 nymph steal objects
1485 * 15 bugbear bite
1486 * 16 osequip bite
1487 *
1488 * char rustarm[ARMORTYPES][2];
1489 * special array for maximum rust damage to armor from rustmonster
1490 * format is: { armor type , minimum attribute
1491 */
1492 #define ARMORTYPES 6
1493 static char rustarm[ARMORTYPES][2] = {
1494 { OSTUDLEATHER, -2 },
1495 { ORING, -4 },
1496 { OCHAIN, -5 },
1497 { OSPLINT, -6 },
1498 { OPLATE, -8 },
1499 { OPLATEARMOR, -9}
1500 };
1501 static char spsel[] = {1, 2, 3, 5, 6, 8, 9, 11, 13, 14};
1502 int
1503 spattack(x, xx, yy)
1504 int x, xx, yy;
1505 {
1506 int i, j = 0, k, m;
1507 const char *p = NULL;
1508
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 }
1521 if ((j == 0) && (k != -1)) {
1522 m = iven[k];
1523 for (i = 0; i < ARMORTYPES; i++)
1524 /* find his armor in table */
1525 if (m == rustarm[i][0]) {
1526 if (--ivenarg[k] < rustarm[i][1])
1527 ivenarg[k] = rustarm[i][1];
1528 else
1529 j = 1;
1530 break;
1531 }
1532 }
1533 if (j == 0) /* if rusting did not occur */
1534 switch (m) {
1535 case OLEATHER:
1536 p = "\nThe %s hit you -- You're lucky you have leather on";
1537 break;
1538 case OSSPLATE:
1539 p = "\nThe %s hit you -- You're fortunate to have stainless steel armor!";
1540 break;
1541 }
1542 else {
1543 beep();
1544 p = "\nThe %s hit you -- your armor feels weaker";
1545 }
1546 break;
1547
1548 case 2:
1549 i = rnd(15) + 8 - c[AC];
1550 spout: p = "\nThe %s breathes fire at you!";
1551 if (c[FIRERESISTANCE])
1552 p = "\nThe %s's flame doesn't faze you!";
1553 else
1554 spout2: if (p) {
1555 lprintf(p, lastmonst);
1556 beep();
1557 }
1558 checkloss(i);
1559 return (0);
1560
1561 case 3:
1562 i = rnd(20) + 25 - c[AC];
1563 goto spout;
1564
1565 case 4:
1566 if (c[STRENGTH] > 3) {
1567 p = "\nThe %s stung you! You feel weaker";
1568 beep();
1569 --c[STRENGTH];
1570 } else
1571 p = "\nThe %s stung you!";
1572 break;
1573
1574 case 5:
1575 p = "\nThe %s blasts you with his cold breath";
1576 i = rnd(15) + 18 - c[AC];
1577 goto spout2;
1578
1579 case 6:
1580 lprintf("\nThe %s drains you of your life energy!", lastmonst);
1581 loselevel();
1582 beep();
1583 return (0);
1584
1585 case 7:
1586 p = "\nThe %s got you with a gusher!";
1587 i = rnd(15) + 25 - c[AC];
1588 goto spout2;
1589
1590 case 8:
1591 if (c[NOTHEFT])
1592 return (0); /* he has a device of no theft */
1593 if (c[GOLD]) {
1594 p = "\nThe %s hit you -- Your purse feels lighter";
1595 if (c[GOLD] > 32767)
1596 c[GOLD] >>= 1;
1597 else
1598 c[GOLD] -= rnd((int) (1 + (c[GOLD] >> 1)));
1599 if (c[GOLD] < 0)
1600 c[GOLD] = 0;
1601 } else
1602 p = "\nThe %s couldn't find any gold to steal";
1603 lprintf(p, lastmonst);
1604 disappear(xx, yy);
1605 beep();
1606 bottomgold();
1607 return (1);
1608
1609 case 9:
1610 for (j = 50;;) {/* disenchant */
1611 i = rund(26);
1612 m = iven[i]; /* randomly select item */
1613 if (m > 0 && ivenarg[i] > 0 && m != OSCROLL && m != OPOTION) {
1614 if ((ivenarg[i] -= 3) < 0)
1615 ivenarg[i] = 0;
1616 lprintf("\nThe %s hits you -- you feel a sense of loss", lastmonst);
1617 srcount = 0;
1618 beep();
1619 show3(i);
1620 bottomline();
1621 return (0);
1622 }
1623 if (--j <= 0) {
1624 p = "\nThe %s nearly misses";
1625 break;
1626 }
1627 break;
1628 }
1629 break;
1630
1631 case 10:
1632 p = "\nThe %s hit you with his barbed tail";
1633 i = rnd(25) - c[AC];
1634 goto spout2;
1635
1636 case 11:
1637 p = "\nThe %s has confused you";
1638 beep();
1639 c[CONFUSE] += 10 + rnd(10);
1640 break;
1641
1642 case 12: /* performs any number of other special
1643 * attacks */
1644 return (spattack(spsel[rund(10)], xx, yy));
1645
1646 case 13:
1647 p = "\nThe %s flattens you with his psionics!";
1648 i = rnd(15) + 30 - c[AC];
1649 goto spout2;
1650
1651 case 14:
1652 if (c[NOTHEFT])
1653 return (0); /* he has device of no theft */
1654 if (emptyhanded() == 1) {
1655 p = "\nThe %s couldn't find anything to steal";
1656 break;
1657 }
1658 lprintf("\nThe %s picks your pocket and takes:", lastmonst);
1659 beep();
1660 if (stealsomething() == 0)
1661 lprcat(" nothing");
1662 disappear(xx, yy);
1663 bottomline();
1664 return (1);
1665
1666 case 15:
1667 i = rnd(10) + 5 - c[AC];
1668 spout3: p = "\nThe %s bit you!";
1669 goto spout2;
1670
1671 case 16:
1672 i = rnd(15) + 10 - c[AC];
1673 goto spout3;
1674 };
1675 if (p) {
1676 lprintf(p, lastmonst);
1677 bottomline();
1678 }
1679 return (0);
1680 }
1681
1682 /*
1683 * checkloss(x) Routine to subtract hp from user and flag bottomline display
1684 * int x;
1685 *
1686 * Routine to subtract hitpoints from the user and flag the bottomline display
1687 * Enter with the number of hit points to lose
1688 * Note: if x > c[HP] this routine could kill the player!
1689 */
1690 void
1691 checkloss(x)
1692 int x;
1693 {
1694 if (x > 0) {
1695 losehp(x);
1696 bottomhp();
1697 }
1698 }
1699
1700 /*
1701 * annihilate() Routine to annihilate all monsters around player (playerx,playery)
1702 *
1703 * Gives player experience, but no dropped objects
1704 * Returns the experience gained from all monsters killed
1705 */
1706 int
1707 annihilate()
1708 {
1709 int i, j;
1710 long k;
1711 u_char *p;
1712 for (k = 0, i = playerx - 1; i <= playerx + 1; i++)
1713 for (j = playery - 1; j <= playery + 1; j++)
1714 if (!vxy(&i, &j)) { /* if not out of bounds */
1715 if (*(p = &mitem[i][j])) { /* if a monster there */
1716 if (*p < DEMONLORD + 2) {
1717 k += monster[*p].experience;
1718 *p = know[i][j] = 0;
1719 } else {
1720 lprintf("\nThe %s barely escapes being annihilated!", monster[*p].name);
1721 hitp[i][j] = (hitp[i][j] >> 1) + 1; /* lose half hit points */
1722 }
1723 }
1724 }
1725 if (k > 0) {
1726 lprcat("\nYou hear loud screams of agony!");
1727 raiseexperience((long) k);
1728 }
1729 return (k);
1730 }
1731
1732 /*
1733 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
1734 * int x,y,dir,lifetime;
1735 *
1736 * Enter with the coordinates of the sphere in x,y
1737 * the direction (0-8 diroffx format) in dir, and the lifespan of the
1738 * sphere in lifetime (in turns)
1739 * Returns the number of spheres currently in existence
1740 */
1741 int
1742 newsphere(x, y, dir, life)
1743 int x, y, dir, life;
1744 {
1745 int m;
1746 struct sphere *sp;
1747 if (((sp = (struct sphere *) malloc(sizeof(struct sphere)))) == 0)
1748 return (c[SPHCAST]); /* can't malloc, therefore failure */
1749 if (dir >= 9)
1750 dir = 0; /* no movement if direction not found */
1751 if (level == 0)
1752 vxy(&x, &y); /* don't go out of bounds */
1753 else {
1754 if (x < 1)
1755 x = 1;
1756 if (x >= MAXX - 1)
1757 x = MAXX - 2;
1758 if (y < 1)
1759 y = 1;
1760 if (y >= MAXY - 1)
1761 y = MAXY - 2;
1762 }
1763 if ((m = mitem[x][y]) >= DEMONLORD + 4) { /* demons dispel spheres */
1764 know[x][y] = 1;
1765 show1cell(x, y);/* show the demon (ha ha) */
1766 cursors();
1767 lprintf("\nThe %s dispels the sphere!", monster[m].name);
1768 beep();
1769 rmsphere(x, y); /* remove any spheres that are here */
1770 free(sp);
1771 return (c[SPHCAST]);
1772 }
1773 if (m == DISENCHANTRESS) { /* disenchantress cancels spheres */
1774 cursors();
1775 lprintf("\nThe %s causes cancellation of the sphere!", monster[m].name);
1776 beep();
1777 boom: sphboom(x, y); /* blow up stuff around sphere */
1778 rmsphere(x, y); /* remove any spheres that are here */
1779 free(sp);
1780 return (c[SPHCAST]);
1781 }
1782 if (c[CANCELLATION]) { /* cancellation cancels spheres */
1783 cursors();
1784 lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!");
1785 beep();
1786 goto boom;
1787 }
1788 if (item[x][y] == OANNIHILATION) { /* collision of spheres
1789 * detonates spheres */
1790 cursors();
1791 lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!");
1792 beep();
1793 rmsphere(x, y);
1794 goto boom;
1795 }
1796 if (playerx == x && playery == y) { /* collision of sphere and
1797 * player! */
1798 cursors();
1799 lprcat("\nYou have been enveloped by the zone of nothingness!\n");
1800 beep();
1801 rmsphere(x, y); /* remove any spheres that are here */
1802 nap(4000);
1803 died(258);
1804 }
1805 item[x][y] = OANNIHILATION;
1806 mitem[x][y] = 0;
1807 know[x][y] = 1;
1808 show1cell(x, y); /* show the new sphere */
1809 sp->x = x;
1810 sp->y = y;
1811 sp->lev = level;
1812 sp->dir = dir;
1813 sp->lifetime = life;
1814 sp->p = 0;
1815 if (spheres == 0)
1816 spheres = sp; /* if first node in the sphere list */
1817 else { /* add sphere to beginning of linked list */
1818 sp->p = spheres;
1819 spheres = sp;
1820 }
1821 return (++c[SPHCAST]); /* one more sphere in the world */
1822 }
1823
1824 /*
1825 * rmsphere(x,y) Function to delete a sphere of annihilation from list
1826 * int x,y;
1827 *
1828 * Enter with the coordinates of the sphere (on current level)
1829 * Returns the number of spheres currently in existence
1830 */
1831 int
1832 rmsphere(x, y)
1833 int x, y;
1834 {
1835 struct sphere *sp, *sp2 = 0;
1836 for (sp = spheres; sp; sp2 = sp, sp = sp->p)
1837 if (level == sp->lev) /* is sphere on this level? */
1838 if ((x == sp->x) && (y == sp->y)) { /* locate sphere at this
1839 * location */
1840 item[x][y] = mitem[x][y] = 0;
1841 know[x][y] = 1;
1842 show1cell(x, y); /* show the now missing
1843 * sphere */
1844 --c[SPHCAST];
1845 if (sp == spheres) {
1846 sp2 = sp;
1847 spheres = sp->p;
1848 free((char *) sp2);
1849 } else {
1850 if (sp2)
1851 sp2->p = sp->p;
1852 free((char *) sp);
1853 }
1854 break;
1855 }
1856 return (c[SPHCAST]); /* return number of spheres in the world */
1857 }
1858
1859 /*
1860 * sphboom(x,y) Function to perform the effects of a sphere detonation
1861 * int x,y;
1862 *
1863 * Enter with the coordinates of the blast, Returns no value
1864 */
1865 void
1866 sphboom(x, y)
1867 int x, y;
1868 {
1869 int i, j;
1870 if (c[HOLDMONST])
1871 c[HOLDMONST] = 1;
1872 if (c[CANCELLATION])
1873 c[CANCELLATION] = 1;
1874 for (j = max(1, x - 2); j < min(x + 3, MAXX - 1); j++)
1875 for (i = max(1, y - 2); i < min(y + 3, MAXY - 1); i++) {
1876 item[j][i] = mitem[j][i] = 0;
1877 show1cell(j, i);
1878 if (playerx == j && playery == i) {
1879 cursors();
1880 beep();
1881 lprcat("\nYou were too close to the sphere!");
1882 nap(3000);
1883 died(283); /* player killed in explosion */
1884 }
1885 }
1886 }
1887
1888 /*
1889 * genmonst() Function to ask for monster and genocide from game
1890 *
1891 * This is done by setting a flag in the monster[] structure
1892 */
1893 void
1894 genmonst()
1895 {
1896 int i, j;
1897 cursors();
1898 lprcat("\nGenocide what monster? ");
1899 for (i = 0; (!isalpha(i)) && (i != ' '); i = lgetchar());
1900 lprc(i);
1901 for (j = 0; j < MAXMONST; j++) /* search for the monster type */
1902 if (monstnamelist[j] == i) { /* have we found it? */
1903 monster[j].genocided = 1; /* genocided from game */
1904 lprintf(" There will be no more %s's", monster[j].name);
1905 /* now wipe out monsters on this level */
1906 newcavelevel(level);
1907 draws(0, MAXX, 0, MAXY);
1908 bot_linex();
1909 return;
1910 }
1911 lprcat(" You sense failure!");
1912 }
1913