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