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