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