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