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