]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/monster.c
Remove dup Hitler fortune. One of the two fortunes I moved yesterday, was
[bsdgames-darwin.git] / larn / monster.c
1 /* $NetBSD: monster.c,v 1.10 2006/03/19 00:37:15 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.10 2006/03/19 00:37:15 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(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 = lgetchar()) == '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 = lgetchar()) == '\33')
244 goto over; /* to escape casting a spell */
245 if ((d = lgetchar()) == '\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 /*
985 * static dirsub(x,y) Routine to ask for direction, then modify x,y for it
986 * int *x,*y;
987 *
988 * Function to ask for a direction and modify an x,y for that direction
989 * Enter with the origination coordinates in (x,y).
990 * Returns index into diroffx[] (0-8).
991 */
992 static int
993 dirsub(x, y)
994 int *x, *y;
995 {
996 int i;
997 lprcat("\nIn What Direction? ");
998 for (i = 0;;)
999 switch (lgetchar()) {
1000 case 'b':
1001 i++;
1002 case 'n':
1003 i++;
1004 case 'y':
1005 i++;
1006 case 'u':
1007 i++;
1008 case 'h':
1009 i++;
1010 case 'k':
1011 i++;
1012 case 'l':
1013 i++;
1014 case 'j':
1015 i++;
1016 goto out;
1017 };
1018 out:
1019 *x = playerx + diroffx[i];
1020 *y = playery + diroffy[i];
1021 vxy(x, y);
1022 return (i);
1023 }
1024
1025 /*
1026 * vxy(x,y) Routine to verify/fix coordinates for being within bounds
1027 * int *x,*y;
1028 *
1029 * Function to verify x & y are within the bounds for a level
1030 * If *x or *y is not within the absolute bounds for a level, fix them so that
1031 * they are on the level.
1032 * Returns TRUE if it was out of bounds, and the *x & *y in the calling
1033 * routine are affected.
1034 */
1035 int
1036 vxy(x, y)
1037 int *x, *y;
1038 {
1039 int flag = 0;
1040 if (*x < 0) {
1041 *x = 0;
1042 flag++;
1043 }
1044 if (*y < 0) {
1045 *y = 0;
1046 flag++;
1047 }
1048 if (*x >= MAXX) {
1049 *x = MAXX - 1;
1050 flag++;
1051 }
1052 if (*y >= MAXY) {
1053 *y = MAXY - 1;
1054 flag++;
1055 }
1056 return (flag);
1057 }
1058
1059 /*
1060 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
1061 * int spnum;
1062 *
1063 * Subroutine to polymorph a monster and ask for the direction its in
1064 * Enter with the spell number in spmun.
1065 * Returns no value.
1066 */
1067 void
1068 dirpoly(spnum)
1069 int spnum;
1070 {
1071 int x, y, m;
1072 if (spnum < 0 || spnum >= SPNUM)
1073 return; /* bad args */
1074 if (isconfuse())
1075 return; /* if he is confused, he can't aim his magic */
1076 dirsub(&x, &y);
1077 if (mitem[x][y] == 0) {
1078 lprcat(" There wasn't anything there!");
1079 return;
1080 }
1081 ifblind(x, y);
1082 if (nospell(spnum, mitem[x][y])) {
1083 lasthx = x;
1084 lasthy = y;
1085 return;
1086 }
1087 while (monster[m = mitem[x][y] = rnd(MAXMONST + 7)].genocided);
1088 hitp[x][y] = monster[m].hitpoints;
1089 show1cell(x, y); /* show the new monster */
1090 }
1091
1092 /*
1093 * hitmonster(x,y) Function to hit a monster at the designated coordinates
1094 * int x,y;
1095 *
1096 * This routine is used for a bash & slash type attack on a monster
1097 * Enter with the coordinates of the monster in (x,y).
1098 * Returns no value.
1099 */
1100 void
1101 hitmonster(x, y)
1102 int x, y;
1103 {
1104 int tmp, monst, damag = 0, flag;
1105 if (c[TIMESTOP])
1106 return; /* not if time stopped */
1107 vxy(&x, &y); /* verify coordinates are within range */
1108 if ((monst = mitem[x][y]) == 0)
1109 return;
1110 hit3flag = 1;
1111 ifblind(x, y);
1112 tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] +
1113 c[WCLASS] / 4 - 12;
1114 cursors();
1115 /* need at least random chance to hit */
1116 if ((rnd(20) < tmp - c[HARDGAME]) || (rnd(71) < 5)) {
1117 lprcat("\nYou hit");
1118 flag = 1;
1119 damag = fullhit(1);
1120 if (damag < 9999)
1121 damag = rnd(damag) + 1;
1122 } else {
1123 lprcat("\nYou missed");
1124 flag = 0;
1125 }
1126 lprcat(" the ");
1127 lprcat(lastmonst);
1128 if (flag) /* if the monster was hit */
1129 if ((monst == RUSTMONSTER) || (monst == DISENCHANTRESS) || (monst == CUBE))
1130 if (c[WIELD] > 0)
1131 if (ivenarg[c[WIELD]] > -10) {
1132 lprintf("\nYour weapon is dulled by the %s", lastmonst);
1133 beep();
1134 --ivenarg[c[WIELD]];
1135 }
1136 if (flag)
1137 hitm(x, y, damag);
1138 if (monst == VAMPIRE)
1139 if (hitp[x][y] < 25) {
1140 mitem[x][y] = BAT;
1141 know[x][y] = 0;
1142 }
1143 }
1144
1145 /*
1146 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
1147 * int x,y,amt;
1148 *
1149 * Returns the number of hitpoints the monster absorbed
1150 * This routine is used to specifically damage a monster at a location (x,y)
1151 * Called by hitmonster(x,y)
1152 */
1153 int
1154 hitm(x, y, amt)
1155 int x, y;
1156 int amt;
1157 {
1158 int monst;
1159 int hpoints, amt2;
1160 vxy(&x, &y); /* verify coordinates are within range */
1161 amt2 = amt; /* save initial damage so we can return it */
1162 monst = mitem[x][y];
1163 if (c[HALFDAM])
1164 amt >>= 1; /* if half damage curse adjust damage points */
1165 if (amt <= 0)
1166 amt2 = amt = 1;
1167 lasthx = x;
1168 lasthy = y;
1169 stealth[x][y] = 1; /* make sure hitting monst breaks stealth
1170 * condition */
1171 c[HOLDMONST] = 0; /* hit a monster breaks hold monster spell */
1172 switch (monst) { /* if a dragon and orb(s) of dragon slaying */
1173 case WHITEDRAGON:
1174 case REDDRAGON:
1175 case GREENDRAGON:
1176 case BRONZEDRAGON:
1177 case PLATINUMDRAGON:
1178 case SILVERDRAGON:
1179 amt *= 1 + (c[SLAYING] << 1);
1180 break;
1181 }
1182 /* invincible monster fix is here */
1183 if (hitp[x][y] > monster[monst].hitpoints)
1184 hitp[x][y] = monster[monst].hitpoints;
1185 if ((hpoints = hitp[x][y]) <= amt) {
1186 #ifdef EXTRA
1187 c[MONSTKILLED]++;
1188 #endif
1189 lprintf("\nThe %s died!", lastmonst);
1190 raiseexperience((long) monster[monst].experience);
1191 amt = monster[monst].gold;
1192 if (amt > 0)
1193 dropgold(rnd(amt) + amt);
1194 dropsomething(monst);
1195 disappear(x, y);
1196 bottomline();
1197 return (hpoints);
1198 }
1199 hitp[x][y] = hpoints - amt;
1200 return (amt2);
1201 }
1202
1203 /*
1204 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
1205 * int x,y;
1206 *
1207 * Function for the monster to hit the player with monster at location x,y
1208 * Returns nothing of value.
1209 */
1210 void
1211 hitplayer(x, y)
1212 int x, y;
1213 {
1214 int dam, tmp, mster, bias;
1215 vxy(&x, &y); /* verify coordinates are within range */
1216 lastnum = mster = mitem[x][y];
1217 /*
1218 * spirit naga's and poltergeist's do nothing if scarab of negate
1219 * spirit
1220 */
1221 if (c[NEGATESPIRIT] || c[SPIRITPRO])
1222 if ((mster == POLTERGEIST) || (mster == SPIRITNAGA))
1223 return;
1224 /* if undead and cube of undead control */
1225 if (c[CUBEofUNDEAD] || c[UNDEADPRO])
1226 if ((mster == VAMPIRE) || (mster == WRAITH) || (mster == ZOMBIE))
1227 return;
1228 if ((know[x][y] & 1) == 0) {
1229 know[x][y] = 1;
1230 show1cell(x, y);
1231 }
1232 bias = (c[HARDGAME]) + 1;
1233 hitflag = hit2flag = hit3flag = 1;
1234 yrepcount = 0;
1235 cursors();
1236 ifblind(x, y);
1237 if (c[INVISIBILITY])
1238 if (rnd(33) < 20) {
1239 lprintf("\nThe %s misses wildly", lastmonst);
1240 return;
1241 }
1242 if (c[CHARMCOUNT])
1243 if (rnd(30) + 5 * monster[mster].level - c[CHARISMA] < 30) {
1244 lprintf("\nThe %s is awestruck at your magnificence!", lastmonst);
1245 return;
1246 }
1247 if (mster == BAT)
1248 dam = 1;
1249 else {
1250 dam = monster[mster].damage;
1251 dam += rnd((int) ((dam < 1) ? 1 : dam)) + monster[mster].level;
1252 }
1253 tmp = 0;
1254 if (monster[mster].attack > 0)
1255 if (((dam + bias + 8) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) {
1256 if (spattack(monster[mster].attack, x, y)) {
1257 flushall();
1258 return;
1259 }
1260 tmp = 1;
1261 bias -= 2;
1262 cursors();
1263 }
1264 if (((dam + bias) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) {
1265 lprintf("\n The %s hit you ", lastmonst);
1266 tmp = 1;
1267 if ((dam -= c[AC]) < 0)
1268 dam = 0;
1269 if (dam > 0) {
1270 losehp(dam);
1271 bottomhp();
1272 flushall();
1273 }
1274 }
1275 if (tmp == 0)
1276 lprintf("\n The %s missed ", lastmonst);
1277 }
1278
1279 /*
1280 * dropsomething(monst) Function to create an object when a monster dies
1281 * int monst;
1282 *
1283 * Function to create an object near the player when certain monsters are killed
1284 * Enter with the monster number
1285 * Returns nothing of value.
1286 */
1287 void
1288 dropsomething(monst)
1289 int monst;
1290 {
1291 switch (monst) {
1292 case ORC:
1293 case NYMPH:
1294 case ELF:
1295 case TROGLODYTE:
1296 case TROLL:
1297 case ROTHE:
1298 case VIOLETFUNGI:
1299 case PLATINUMDRAGON:
1300 case GNOMEKING:
1301 case REDDRAGON:
1302 something(level);
1303 return;
1304
1305 case LEPRECHAUN:
1306 if (rnd(101) >= 75)
1307 creategem();
1308 if (rnd(5) == 1)
1309 dropsomething(LEPRECHAUN);
1310 return;
1311 }
1312 }
1313
1314 /*
1315 * dropgold(amount) Function to drop some gold around player
1316 * int amount;
1317 *
1318 * Enter with the number of gold pieces to drop
1319 * Returns nothing of value.
1320 */
1321 void
1322 dropgold(amount)
1323 int amount;
1324 {
1325 if (amount > 250)
1326 createitem(OMAXGOLD, amount / 100);
1327 else
1328 createitem(OGOLDPILE, amount);
1329 }
1330
1331 /*
1332 * something(level) Function to create a random item around player
1333 * int level;
1334 *
1335 * Function to create an item from a designed probability around player
1336 * Enter with the cave level on which something is to be dropped
1337 * Returns nothing of value.
1338 */
1339 void
1340 something(level)
1341 int level;
1342 {
1343 int j;
1344 int i;
1345 if (level < 0 || level > MAXLEVEL + MAXVLEVEL)
1346 return; /* correct level? */
1347 if (rnd(101) < 8)
1348 something(level); /* possibly more than one item */
1349 j = newobject(level, &i);
1350 createitem(j, i);
1351 }
1352
1353 /*
1354 * newobject(lev,i) Routine to return a randomly selected new object
1355 * int lev,*i;
1356 *
1357 * Routine to return a randomly selected object to be created
1358 * Returns the object number created, and sets *i for its argument
1359 * Enter with the cave level and a pointer to the items arg
1360 */
1361 static char nobjtab[] = {
1362 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION, OPOTION,
1363 OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE,
1364 OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER,
1365 OLEATHER, OLEATHER, OLEATHER, OREGENRING, OPROTRING,
1366 OENERGYRING, ODEXRING, OSTRRING, OSPEAR, OBELT, ORING,
1367 OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
1368 OLONGSWORD};
1369
1370 int
1371 newobject(lev, i)
1372 int lev, *i;
1373 {
1374 int tmp = 32, j;
1375 if (level < 0 || level > MAXLEVEL + MAXVLEVEL)
1376 return (0); /* correct level? */
1377 if (lev > 6)
1378 tmp = 37;
1379 else if (lev > 4)
1380 tmp = 35;
1381 j = nobjtab[tmp = rnd(tmp)]; /* the object type */
1382 switch (tmp) {
1383 case 1:
1384 case 2:
1385 case 3:
1386 case 4:
1387 *i = newscroll();
1388 break;
1389 case 5:
1390 case 6:
1391 case 7:
1392 case 8:
1393 *i = newpotion();
1394 break;
1395 case 9:
1396 case 10:
1397 case 11:
1398 case 12:
1399 *i = rnd((lev + 1) * 10) + lev * 10 + 10;
1400 break;
1401 case 13:
1402 case 14:
1403 case 15:
1404 case 16:
1405 *i = lev;
1406 break;
1407 case 17:
1408 case 18:
1409 case 19:
1410 if (!(*i = newdagger()))
1411 return (0);
1412 break;
1413 case 20:
1414 case 21:
1415 case 22:
1416 if (!(*i = newleather()))
1417 return (0);
1418 break;
1419 case 23:
1420 case 32:
1421 case 35:
1422 *i = rund(lev / 3 + 1);
1423 break;
1424 case 24:
1425 case 26:
1426 *i = rnd(lev / 4 + 1);
1427 break;
1428 case 25:
1429 *i = rund(lev / 4 + 1);
1430 break;
1431 case 27:
1432 *i = rnd(lev / 2 + 1);
1433 break;
1434 case 30:
1435 case 33:
1436 *i = rund(lev / 2 + 1);
1437 break;
1438 case 28:
1439 *i = rund(lev / 3 + 1);
1440 if (*i == 0)
1441 return (0);
1442 break;
1443 case 29:
1444 case 31:
1445 *i = rund(lev / 2 + 1);
1446 if (*i == 0)
1447 return (0);
1448 break;
1449 case 34:
1450 *i = newchain();
1451 break;
1452 case 36:
1453 *i = newplate();
1454 break;
1455 case 37:
1456 *i = newsword();
1457 break;
1458 }
1459 return (j);
1460 }
1461
1462 /*
1463 * spattack(atckno,xx,yy) Function to process special attacks from monsters
1464 * int atckno,xx,yy;
1465 *
1466 * Enter with the special attack number, and the coordinates (xx,yy)
1467 * of the monster that is special attacking
1468 * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
1469 *
1470 * atckno monster effect
1471 * ---------------------------------------------------
1472 * 0 none
1473 * 1 rust monster eat armor
1474 * 2 hell hound breathe light fire
1475 * 3 dragon breathe fire
1476 * 4 giant centipede weakening sing
1477 * 5 white dragon cold breath
1478 * 6 wraith drain level
1479 * 7 waterlord water gusher
1480 * 8 leprechaun steal gold
1481 * 9 disenchantress disenchant weapon or armor
1482 * 10 ice lizard hits with barbed tail
1483 * 11 umber hulk confusion
1484 * 12 spirit naga cast spells taken from special attacks
1485 * 13 platinum dragon psionics
1486 * 14 nymph steal objects
1487 * 15 bugbear bite
1488 * 16 osequip bite
1489 *
1490 * char rustarm[ARMORTYPES][2];
1491 * special array for maximum rust damage to armor from rustmonster
1492 * format is: { armor type , minimum attribute
1493 */
1494 #define ARMORTYPES 6
1495 static char rustarm[ARMORTYPES][2] = {
1496 { OSTUDLEATHER, -2 },
1497 { ORING, -4 },
1498 { OCHAIN, -5 },
1499 { OSPLINT, -6 },
1500 { OPLATE, -8 },
1501 { OPLATEARMOR, -9}
1502 };
1503 static char spsel[] = {1, 2, 3, 5, 6, 8, 9, 11, 13, 14};
1504 int
1505 spattack(x, xx, yy)
1506 int x, xx, yy;
1507 {
1508 int i, j = 0, k, m;
1509 char *p = 0;
1510 if (c[CANCELLATION])
1511 return (0);
1512 vxy(&xx, &yy); /* verify x & y coordinates */
1513 switch (x) {
1514 case 1: /* rust your armor, j=1 when rusting has occurred */
1515 m = k = c[WEAR];
1516 if ((i = c[SHIELD]) != -1) {
1517 if (--ivenarg[i] < -1)
1518 ivenarg[i] = -1;
1519 else
1520 j = 1;
1521 }
1522 if ((j == 0) && (k != -1)) {
1523 m = iven[k];
1524 for (i = 0; i < ARMORTYPES; i++)
1525 /* find his armor in table */
1526 if (m == rustarm[i][0]) {
1527 if (--ivenarg[k] < rustarm[i][1])
1528 ivenarg[k] = rustarm[i][1];
1529 else
1530 j = 1;
1531 break;
1532 }
1533 }
1534 if (j == 0) /* if rusting did not occur */
1535 switch (m) {
1536 case OLEATHER:
1537 p = "\nThe %s hit you -- Your lucky you have leather on";
1538 break;
1539 case OSSPLATE:
1540 p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
1541 break;
1542 }
1543 else {
1544 beep();
1545 p = "\nThe %s hit you -- your armor feels weaker";
1546 }
1547 break;
1548
1549 case 2:
1550 i = rnd(15) + 8 - c[AC];
1551 spout: p = "\nThe %s breathes fire at you!";
1552 if (c[FIRERESISTANCE])
1553 p = "\nThe %s's flame doesn't phase you!";
1554 else
1555 spout2: if (p) {
1556 lprintf(p, lastmonst);
1557 beep();
1558 }
1559 checkloss(i);
1560 return (0);
1561
1562 case 3:
1563 i = rnd(20) + 25 - c[AC];
1564 goto spout;
1565
1566 case 4:
1567 if (c[STRENGTH] > 3) {
1568 p = "\nThe %s stung you! You feel weaker";
1569 beep();
1570 --c[STRENGTH];
1571 } else
1572 p = "\nThe %s stung you!";
1573 break;
1574
1575 case 5:
1576 p = "\nThe %s blasts you with his cold breath";
1577 i = rnd(15) + 18 - c[AC];
1578 goto spout2;
1579
1580 case 6:
1581 lprintf("\nThe %s drains you of your life energy!", lastmonst);
1582 loselevel();
1583 beep();
1584 return (0);
1585
1586 case 7:
1587 p = "\nThe %s got you with a gusher!";
1588 i = rnd(15) + 25 - c[AC];
1589 goto spout2;
1590
1591 case 8:
1592 if (c[NOTHEFT])
1593 return (0); /* he has a device of no theft */
1594 if (c[GOLD]) {
1595 p = "\nThe %s hit you -- Your purse feels lighter";
1596 if (c[GOLD] > 32767)
1597 c[GOLD] >>= 1;
1598 else
1599 c[GOLD] -= rnd((int) (1 + (c[GOLD] >> 1)));
1600 if (c[GOLD] < 0)
1601 c[GOLD] = 0;
1602 } else
1603 p = "\nThe %s couldn't find any gold to steal";
1604 lprintf(p, lastmonst);
1605 disappear(xx, yy);
1606 beep();
1607 bottomgold();
1608 return (1);
1609
1610 case 9:
1611 for (j = 50;;) {/* disenchant */
1612 i = rund(26);
1613 m = iven[i]; /* randomly select item */
1614 if (m > 0 && ivenarg[i] > 0 && m != OSCROLL && m != OPOTION) {
1615 if ((ivenarg[i] -= 3) < 0)
1616 ivenarg[i] = 0;
1617 lprintf("\nThe %s hits you -- you feel a sense of loss", lastmonst);
1618 srcount = 0;
1619 beep();
1620 show3(i);
1621 bottomline();
1622 return (0);
1623 }
1624 if (--j <= 0) {
1625 p = "\nThe %s nearly misses";
1626 break;
1627 }
1628 break;
1629 }
1630 break;
1631
1632 case 10:
1633 p = "\nThe %s hit you with his barbed tail";
1634 i = rnd(25) - c[AC];
1635 goto spout2;
1636
1637 case 11:
1638 p = "\nThe %s has confused you";
1639 beep();
1640 c[CONFUSE] += 10 + rnd(10);
1641 break;
1642
1643 case 12: /* performs any number of other special
1644 * attacks */
1645 return (spattack(spsel[rund(10)], xx, yy));
1646
1647 case 13:
1648 p = "\nThe %s flattens you with his psionics!";
1649 i = rnd(15) + 30 - c[AC];
1650 goto spout2;
1651
1652 case 14:
1653 if (c[NOTHEFT])
1654 return (0); /* he has device of no theft */
1655 if (emptyhanded() == 1) {
1656 p = "\nThe %s couldn't find anything to steal";
1657 break;
1658 }
1659 lprintf("\nThe %s picks your pocket and takes:", lastmonst);
1660 beep();
1661 if (stealsomething() == 0)
1662 lprcat(" nothing");
1663 disappear(xx, yy);
1664 bottomline();
1665 return (1);
1666
1667 case 15:
1668 i = rnd(10) + 5 - c[AC];
1669 spout3: p = "\nThe %s bit you!";
1670 goto spout2;
1671
1672 case 16:
1673 i = rnd(15) + 10 - c[AC];
1674 goto spout3;
1675 };
1676 if (p) {
1677 lprintf(p, lastmonst);
1678 bottomline();
1679 }
1680 return (0);
1681 }
1682
1683 /*
1684 * checkloss(x) Routine to subtract hp from user and flag bottomline display
1685 * int x;
1686 *
1687 * Routine to subtract hitpoints from the user and flag the bottomline display
1688 * Enter with the number of hit points to lose
1689 * Note: if x > c[HP] this routine could kill the player!
1690 */
1691 void
1692 checkloss(x)
1693 int x;
1694 {
1695 if (x > 0) {
1696 losehp(x);
1697 bottomhp();
1698 }
1699 }
1700
1701 /*
1702 * annihilate() Routine to annihilate all monsters around player (playerx,playery)
1703 *
1704 * Gives player experience, but no dropped objects
1705 * Returns the experience gained from all monsters killed
1706 */
1707 int
1708 annihilate()
1709 {
1710 int i, j;
1711 long k;
1712 u_char *p;
1713 for (k = 0, i = playerx - 1; i <= playerx + 1; i++)
1714 for (j = playery - 1; j <= playery + 1; j++)
1715 if (!vxy(&i, &j)) { /* if not out of bounds */
1716 if (*(p = &mitem[i][j])) { /* if a monster there */
1717 if (*p < DEMONLORD + 2) {
1718 k += monster[*p].experience;
1719 *p = know[i][j] = 0;
1720 } else {
1721 lprintf("\nThe %s barely escapes being annihilated!", monster[*p].name);
1722 hitp[i][j] = (hitp[i][j] >> 1) + 1; /* lose half hit points */
1723 }
1724 }
1725 }
1726 if (k > 0) {
1727 lprcat("\nYou hear loud screams of agony!");
1728 raiseexperience((long) k);
1729 }
1730 return (k);
1731 }
1732
1733 /*
1734 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
1735 * int x,y,dir,lifetime;
1736 *
1737 * Enter with the coordinates of the sphere in x,y
1738 * the direction (0-8 diroffx format) in dir, and the lifespan of the
1739 * sphere in lifetime (in turns)
1740 * Returns the number of spheres currently in existence
1741 */
1742 int
1743 newsphere(x, y, dir, life)
1744 int x, y, dir, life;
1745 {
1746 int m;
1747 struct sphere *sp;
1748 if (((sp = (struct sphere *) malloc(sizeof(struct sphere)))) == 0)
1749 return (c[SPHCAST]); /* can't malloc, therefore failure */
1750 if (dir >= 9)
1751 dir = 0; /* no movement if direction not found */
1752 if (level == 0)
1753 vxy(&x, &y); /* don't go out of bounds */
1754 else {
1755 if (x < 1)
1756 x = 1;
1757 if (x >= MAXX - 1)
1758 x = MAXX - 2;
1759 if (y < 1)
1760 y = 1;
1761 if (y >= MAXY - 1)
1762 y = MAXY - 2;
1763 }
1764 if ((m = mitem[x][y]) >= DEMONLORD + 4) { /* demons dispel spheres */
1765 know[x][y] = 1;
1766 show1cell(x, y);/* show the demon (ha ha) */
1767 cursors();
1768 lprintf("\nThe %s dispels the sphere!", monster[m].name);
1769 beep();
1770 rmsphere(x, y); /* remove any spheres that are here */
1771 free(sp);
1772 return (c[SPHCAST]);
1773 }
1774 if (m == DISENCHANTRESS) { /* disenchantress cancels spheres */
1775 cursors();
1776 lprintf("\nThe %s causes cancellation of the sphere!", monster[m].name);
1777 beep();
1778 boom: sphboom(x, y); /* blow up stuff around sphere */
1779 rmsphere(x, y); /* remove any spheres that are here */
1780 free(sp);
1781 return (c[SPHCAST]);
1782 }
1783 if (c[CANCELLATION]) { /* cancellation cancels spheres */
1784 cursors();
1785 lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!");
1786 beep();
1787 goto boom;
1788 }
1789 if (item[x][y] == OANNIHILATION) { /* collision of spheres
1790 * detonates spheres */
1791 cursors();
1792 lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!");
1793 beep();
1794 rmsphere(x, y);
1795 goto boom;
1796 }
1797 if (playerx == x && playery == y) { /* collision of sphere and
1798 * player! */
1799 cursors();
1800 lprcat("\nYou have been enveloped by the zone of nothingness!\n");
1801 beep();
1802 rmsphere(x, y); /* remove any spheres that are here */
1803 nap(4000);
1804 died(258);
1805 }
1806 item[x][y] = OANNIHILATION;
1807 mitem[x][y] = 0;
1808 know[x][y] = 1;
1809 show1cell(x, y); /* show the new sphere */
1810 sp->x = x;
1811 sp->y = y;
1812 sp->lev = level;
1813 sp->dir = dir;
1814 sp->lifetime = life;
1815 sp->p = 0;
1816 if (spheres == 0)
1817 spheres = sp; /* if first node in the sphere list */
1818 else { /* add sphere to beginning of linked list */
1819 sp->p = spheres;
1820 spheres = sp;
1821 }
1822 return (++c[SPHCAST]); /* one more sphere in the world */
1823 }
1824
1825 /*
1826 * rmsphere(x,y) Function to delete a sphere of annihilation from list
1827 * int x,y;
1828 *
1829 * Enter with the coordinates of the sphere (on current level)
1830 * Returns the number of spheres currently in existence
1831 */
1832 int
1833 rmsphere(x, y)
1834 int x, y;
1835 {
1836 struct sphere *sp, *sp2 = 0;
1837 for (sp = spheres; sp; sp2 = sp, sp = sp->p)
1838 if (level == sp->lev) /* is sphere on this level? */
1839 if ((x == sp->x) && (y == sp->y)) { /* locate sphere at this
1840 * location */
1841 item[x][y] = mitem[x][y] = 0;
1842 know[x][y] = 1;
1843 show1cell(x, y); /* show the now missing
1844 * sphere */
1845 --c[SPHCAST];
1846 if (sp == spheres) {
1847 sp2 = sp;
1848 spheres = sp->p;
1849 free((char *) sp2);
1850 } else {
1851 if (sp2)
1852 sp2->p = sp->p;
1853 free((char *) sp);
1854 }
1855 break;
1856 }
1857 return (c[SPHCAST]); /* return number of spheres in the world */
1858 }
1859
1860 /*
1861 * sphboom(x,y) Function to perform the effects of a sphere detonation
1862 * int x,y;
1863 *
1864 * Enter with the coordinates of the blast, Returns no value
1865 */
1866 void
1867 sphboom(x, y)
1868 int x, y;
1869 {
1870 int i, j;
1871 if (c[HOLDMONST])
1872 c[HOLDMONST] = 1;
1873 if (c[CANCELLATION])
1874 c[CANCELLATION] = 1;
1875 for (j = max(1, x - 2); j < min(x + 3, MAXX - 1); j++)
1876 for (i = max(1, y - 2); i < min(y + 3, MAXY - 1); i++) {
1877 item[j][i] = mitem[j][i] = 0;
1878 show1cell(j, i);
1879 if (playerx == j && playery == i) {
1880 cursors();
1881 beep();
1882 lprcat("\nYou were too close to the sphere!");
1883 nap(3000);
1884 died(283); /* player killed in explosion */
1885 }
1886 }
1887 }
1888
1889 /*
1890 * genmonst() Function to ask for monster and genocide from game
1891 *
1892 * This is done by setting a flag in the monster[] structure
1893 */
1894 void
1895 genmonst()
1896 {
1897 int i, j;
1898 cursors();
1899 lprcat("\nGenocide what monster? ");
1900 for (i = 0; (!isalpha(i)) && (i != ' '); i = lgetchar());
1901 lprc(i);
1902 for (j = 0; j < MAXMONST; j++) /* search for the monster type */
1903 if (monstnamelist[j] == i) { /* have we found it? */
1904 monster[j].genocided = 1; /* genocided from game */
1905 lprintf(" There will be no more %s's", monster[j].name);
1906 /* now wipe out monsters on this level */
1907 newcavelevel(level);
1908 draws(0, MAXX, 0, MAXY);
1909 bot_linex();
1910 return;
1911 }
1912 lprcat(" You sense failure!");
1913 }