]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/monster.c
2 static char rcsid
[] = "$NetBSD: monster.c,v 1.4 1995/04/24 12:24:05 cgd Exp $";
6 * monster.c Larn is copyrighted 1986 by Noah Morgan.
8 * This file contains the following functions:
9 * ----------------------------------------------------------------------------
11 * createmonster(monstno) Function to create a monster next to the player
14 * int cgood(x,y,itm,monst) Function to check location for emptiness
17 * createitem(it,arg) Routine to place an item next to the player
20 * cast() Subroutine called by parse to cast a spell for the user
22 * speldamage(x) Function to perform spell functions cast by the player
25 * loseint() Routine to decrement your int (intelligence) if > 3
27 * isconfuse() Routine to check to see if player is confused
29 * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
32 * fullhit(xx) Function to return full damage against a monst (aka web)
35 * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
39 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
40 * int spnum,dam,delay;
43 * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
46 * tdirect(spnum) Routine to teleport away a monster
49 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
53 * dirsub(x,y) Routine to ask for direction, then modify x,y for it
56 * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds
59 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
62 * hitmonster(x,y) Function to hit a monster at the designated coordinates
65 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
68 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
71 * dropsomething(monst) Function to create an object when a monster dies
74 * dropgold(amount) Function to drop some gold around player
77 * something(level) Function to create a random item around player
80 * newobject(lev,i) Routine to return a randomly selected new object
83 * spattack(atckno,xx,yy) Function to process special attacks from monsters
86 * checkloss(x) Routine to subtract hp from user and flag bottomline display
89 * annihilate() Routine to annihilate monsters around player, playerx,playery
91 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
92 * int x,y,dir,lifetime;
94 * rmsphere(x,y) Function to delete a sphere of annihilation from list
97 * sphboom(x,y) Function to perform the effects of a sphere detonation
100 * genmonst() Function to ask for monster and genocide from game
106 struct isave
/* used for altar reality */
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 */
114 * createmonster(monstno) Function to create a monster next to the player
117 * Enter with the monster number (1 to MAXMONST+8)
123 register int x
,y
,k
,i
;
124 if (mon
<1 || mon
>MAXMONST
+8) /* check for monster number out of bounds */
126 beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon
); nap(3000); return;
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 */
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 */
136 hitp
[x
][y
] = monster
[mon
].hitpoints
;
137 stealth
[x
][y
]=know
[x
][y
]=0;
140 case ROTHE
: case POLTERGEIST
: case VAMPIRE
: stealth
[x
][y
]=1;
148 * int cgood(x,y,itm,monst) Function to check location for emptiness
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
158 int cgood(x
,y
,itm
,monst
)
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 */
172 * createitem(it,arg) Routine to place an item next to the player
175 * Enter with the item number and its argument (iven[], ivenarg[])
176 * Returns no value, thus we don't know about createitem() failures.
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 */
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 */
189 item
[x
][y
] = it
; know
[x
][y
]=0; iarg
[x
][y
]=arg
; return;
195 * cast() Subroutine called by parse to cast a spell for the user
197 * No arguments and no return value.
199 static char eys
[] = "\nEnter your spell: ";
202 register int i
,j
,a
,b
,d
;
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 */
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
))
218 { speldamage(i
); j
= 1; i
=SPNUM
; }
220 if (j
== -1) lprcat(" Nothing Happened ");
227 * speldamage(x) Function to perform spell functions cast by the player
230 * Enter with the spell number, returns no value.
231 * Please insure that there are 2 spaces before all messages here
236 register int i
,j
,clev
;
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 */
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; }
248 /* ----- LEVEL 1 SPELLS ----- */
250 case 0: if (c
[PROTECTIONTIME
]==0) c
[MOREDEFENSES
]+=2; /* protection field +2 */
251 c
[PROTECTIONTIME
] += 250; return;
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 */
258 case 2: if (c
[DEXCOUNT
]==0) c
[DEXTERITY
]+=3; /* dexterity */
259 c
[DEXCOUNT
] += 400; return;
262 p
=" While the %s slept, you smashed it %d times";
263 ws
: direct(x
,fullhit(i
),p
,i
); /* sleep */ return;
265 case 4: /* charm monster */ c
[CHARMCOUNT
] += c
[CHARISMA
]<<1; return;
267 case 5: godirect(x
,rnd(10)+15+clev
," The sound damages the %s",70,'@'); /* sonic spear */
270 /* ----- LEVEL 2 SPELLS ----- */
272 case 6: i
=rnd(3)+2; p
=" While the %s is entangled, you hit %d times";
275 case 7: if (c
[STRCOUNT
]==0) c
[STREXTRA
]+=3; /* strength */
276 c
[STRCOUNT
] += 150+rnd(100); return;
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;
285 case 9: raisehp(20+(clev
<<1)); return; /* healing */
287 case 10: c
[BLINDCOUNT
]=0; return; /* cure blindness */
289 case 11: createmonster(makemonst(level
+1)+8); return;
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!");
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;
300 /* ----- LEVEL 3 SPELLS ----- */
302 case 14: godirect(x
,rnd(25+clev
)+25+clev
," The fireball hits the %s",40,'*'); return; /* fireball */
304 case 15: godirect(x
,rnd(25)+20+clev
," Your cone of cold strikes the %s",60,'O'); /* cold */
307 case 16: dirpoly(x
); return; /* polymorph */
309 case 17: c
[CANCELLATION
]+= 5+clev
; return; /* cancellation */
311 case 18: c
[HASTESELF
]+= 7+clev
; return; /* haste self */
313 case 19: omnidirect(x
,30+rnd(10)," The %s gasps for air"); /* cloud kill */
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
++)
320 kn
= &know
[i
][j
]; pm
= &mitem
[i
][j
];
321 switch(*(p
= &item
[i
][j
]))
323 case OWALL
: if (level
< MAXLEVEL
+MAXVLEVEL
-1)
327 case OSTATUE
: if (c
[HARDGAME
]<3)
329 *p
=OBOOK
; iarg
[i
][j
]=level
; *kn
=0;
333 case OTHRONE
: *pm
=GNOMEKING
; *kn
=0; *p
= OTHRONE2
;
334 hitp
[i
][j
]=monster
[GNOMEKING
].hitpoints
; break;
336 case OALTAR
: *pm
=DEMONPRINCE
; *kn
=0;
337 hitp
[i
][j
]=monster
[DEMONPRINCE
].hitpoints
; break;
341 case XORN
: ifblind(i
,j
); hitm(i
,j
,200); break; /* Xorn takes damage from vpr */
346 /* ----- LEVEL 4 SPELLS ----- */
348 case 21: direct(x
,100+clev
," The %s shrivels up",0); /* dehydration */
351 case 22: godirect(x
,rnd(25)+20+(clev
<<1)," A lightning bolt hits the %s",1,'~'); /* lightning */
354 case 23: i
=min(c
[HP
]-1,c
[HPMAX
]/2); /* drain life */
355 direct(x
,i
+i
,"",0); c
[HP
] -= i
; return;
357 case 24: if (c
[GLOBE
]==0) c
[MOREDEFENSES
] += 10;
358 c
[GLOBE
] += 200; loseint(); /* globe of invulnerability */
361 case 25: omnidirect(x
,32+clev
," The %s struggles for air in your flood!"); /* flood */
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;
368 /* ----- LEVEL 5 SPELLS ----- */
370 case 27: c
[SCAREMONST
] += rnd(10)+clev
; return; /* scare monster */
372 case 28: c
[HOLDMONST
] += rnd(10)+clev
; return; /* hold monster */
374 case 29: c
[TIMESTOP
] += rnd(20)+(clev
<<1); return; /* time stop */
376 case 30: tdirect(x
); return; /* teleport away */
378 case 31: omnidirect(x
,35+rnd(10)+clev
," The %s cringes from the flame"); /* magic fire */
381 /* ----- LEVEL 6 SPELLS ----- */
383 case 32: if ((rnd(23)==5) && (wizard
==0)) /* sphere of annihilation */
385 beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
386 nap(4000); died(258); return;
388 xl
=playerx
; yl
=playery
;
390 i
=dirsub(&xl
,&yl
); /* get direction of sphere */
391 newsphere(xl
,yl
,i
,rnd(20)+11); /* make a sphere */
394 case 33: genmonst(); spelknow
[33]=0; /* genocide */
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;
405 case 35: /* walk through walls */
406 c
[WTW
] += rnd(10)+5; return;
408 case 36: /* alter reality */
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 */
417 if (xl
&& xl
!=OWALL
&& xl
!=OANNIHILATION
)
419 save
[sc
].type
=0; save
[sc
].id
=item
[i
][j
];
420 save
[sc
++].arg
=iarg
[i
][j
];
424 save
[sc
].type
=1; save
[sc
].id
=mitem
[i
][j
];
425 save
[sc
++].arg
=hitp
[i
][j
];
427 item
[i
][j
]=OWALL
; mitem
[i
][j
]=0;
428 if (wizard
) know
[i
][j
]=1; else know
[i
][j
]=0;
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 */
435 if (save
[sc
].type
== 0)
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
; }
442 { /* put monsters back in */
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
; }
449 draws(0,MAXX
,0,MAXY
); if (wizard
==0) spelknow
[36]=0;
450 free((char*)save
); positionplayer(); return;
453 case 37: /* permanence */ adjtime(-99999L); spelknow
[37]=0; /* forget */
457 default: lprintf(" spell %d not available!",(long)x
); beep(); return;
462 * loseint() Routine to subtract 1 from your int (intelligence) if > 3
464 * No arguments and no return value
468 if (--c
[INTELLIGENCE
]<3) c
[INTELLIGENCE
]=3;
472 * isconfuse() Routine to check to see if player is confused
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
479 if (c
[CONFUSE
]) { lprcat(" You can't aim your magic!"); beep(); }
484 * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
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.
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);
501 * fullhit(xx) Function to return full damage against a monster (aka web)
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
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
);
518 * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
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.
527 direct(spnum
,dam
,str
,arg
)
533 if (spnum
<0 || spnum
>=SPNUM
|| str
==0) return; /* bad arguments */
534 if (isconfuse()) return;
537 if (item
[x
][y
]==OMIRROR
)
539 if (spnum
==3) /* sleep */
541 lprcat("You fall asleep! "); beep();
544 while (arg
-- > 0) { parse2(); nap(1000); }
547 else if (spnum
==6) /* web */
549 lprcat("You get stuck in your own web! "); beep();
555 lprintf(str
,"spell caster (thats you)",(long)arg
);
556 beep(); losehp(dam
); return;
560 { lprcat(" There wasn't anything there!"); return; }
562 if (nospell(spnum
,m
)) { lasthx
=x
; lasthy
=y
; return; }
563 lprintf(str
,lastmonst
,(long)arg
); hitm(x
,y
,dam
);
567 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
568 * int spnum,dam,delay;
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.
578 godirect(spnum
,dam
,str
,delay
,cshow
)
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
;
592 if ((x
> MAXX
-1) || (y
> MAXY
-1) || (x
< 0) || (y
< 0))
594 dam
=0; break; /* out of bounds */
596 if ((x
==playerx
) && (y
==playery
)) /* if energy hits player */
598 cursors(); lprcat("\nYou are hit my your own magic!"); beep();
599 lastnum
=278; losehp(dam
); return;
601 if (c
[BLINDCOUNT
]==0) /* if not blind show effect */
603 cursor(x
+1,y
+1); lprc(cshow
); nap(delay
); show1cell(x
,y
);
605 if ((m
=mitem
[x
][y
])) /* is there a monster there? */
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
;
613 else switch (*(p
= &item
[x
][y
]))
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
))
620 lprcat(" The wall crumbles");
625 god2
: dam
= 0; break;
627 case OCLOSEDDOOR
: cursors(); lprc('\n'); lprintf(str
,"door");
630 lprcat(" The door is blasted apart");
635 case OSTATUE
: cursors(); lprc('\n'); lprintf(str
,"statue");
639 lprcat(" The statue crumbles");
640 *p
=OBOOK
; iarg
[x
][y
]=level
;
645 case OTHRONE
: cursors(); lprc('\n'); lprintf(str
,"throne");
648 mitem
[x
][y
]=GNOMEKING
; hitp
[x
][y
]=monster
[GNOMEKING
].hitpoints
;
654 case OMIRROR
: dx
*= -1; dy
*= -1; break;
656 dam
-= 3 + (c
[HARDGAME
]>>1);
661 * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
664 * Subroutine to copy the word "monster" into lastmonst if the player is blind
665 * Enter with the coordinates (x,y) of the monster
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
; }
679 * tdirect(spnum) Routine to teleport away a monster
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
691 if (spnum
<0 || spnum
>=SPNUM
) return; /* bad args */
692 if (isconfuse()) return;
694 if ((m
=mitem
[x
][y
])==0)
695 { lprcat(" There wasn't anything there!"); return; }
697 if (nospell(spnum
,m
)) { lasthx
=x
; lasthy
=y
; return; }
698 fillmonst(m
); mitem
[x
][y
]=know
[x
][y
]=0;
702 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
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.
711 omnidirect(spnum
,dam
,str
)
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
++)
721 if (nospell(spnum
,m
) == 0)
724 cursors(); lprc('\n'); lprintf(str
,lastmonst
);
725 hitm(x
,y
,dam
); nap(800);
727 else { lasthx
=x
; lasthy
=y
; }
732 * static dirsub(x,y) Routine to ask for direction, then modify x,y for it
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).
744 lprcat("\nIn What Direction? ");
755 case 'j': i
++; goto out
;
758 *x
= playerx
+diroffx
[i
]; *y
= playery
+diroffy
[i
];
763 * vxy(x,y) Routine to verify/fix coordinates for being within bounds
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.
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
++; }
784 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
787 * Subroutine to polymorph a monster and ask for the direction its in
788 * Enter with the spell number in spmun.
795 if (spnum
<0 || spnum
>=SPNUM
) return; /* bad args */
796 if (isconfuse()) return; /* if he is confused, he can't aim his magic */
799 { lprcat(" There wasn't anything there!"); return; }
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 */
808 * hitmonster(x,y) Function to hit a monster at the designated coordinates
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).
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;
825 if ((rnd(20) < tmp
-c
[HARDGAME
]) || (rnd(71) < 5)) /* need at least random chance to hit */
827 lprcat("\nYou hit"); flag
=1;
829 if (damag
<9999) damag
=rnd(damag
)+1;
833 lprcat("\nYou missed"); flag
=0;
835 lprcat(" the "); lprcat(lastmonst
);
836 if (flag
) /* if the monster was hit */
837 if ((monst
==RUSTMONSTER
) || (monst
==DISENCHANTRESS
) || (monst
==CUBE
))
839 if (ivenarg
[c
[WIELD
]] > -10)
841 lprintf("\nYour weapon is dulled by the %s",lastmonst
); beep();
844 if (flag
) hitm(x
,y
,damag
);
845 if (monst
== VAMPIRE
) if (hitp
[x
][y
]<25) { mitem
[x
][y
]=BAT
; know
[x
][y
]=0; }
849 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
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)
862 vxy(&x
,&y
); /* verify coordinates are within range */
863 amt2
= amt
; /* save initial damage so we can return it */
865 if (c
[HALFDAM
]) amt
>>= 1; /* if half damage curse adjust damage points */
866 if (amt
<=0) amt2
= amt
= 1;
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 */
872 case WHITEDRAGON
: case REDDRAGON
: case GREENDRAGON
:
873 case BRONZEDRAGON
: case PLATINUMDRAGON
: case SILVERDRAGON
:
874 amt
*= 1+(c
[SLAYING
]<<1); break;
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
)
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();
890 hitp
[x
][y
] = hpoints
-amt
; return(amt2
);
894 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
897 * Function for the monster to hit the player with monster at location x,y
898 * Returns nothing of value.
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)
912 know
[x
][y
]=1; show1cell(x
,y
);
914 bias
= (c
[HARDGAME
]) + 1;
915 hitflag
= hit2flag
= hit3flag
= 1;
917 cursors(); ifblind(x
,y
);
918 if (c
[INVISIBILITY
]) if (rnd(33)<20)
920 lprintf("\nThe %s misses wildly",lastmonst
); return;
922 if (c
[CHARMCOUNT
]) if (rnd(30)+5*monster
[mster
].level
-c
[CHARISMA
]<30)
924 lprintf("\nThe %s is awestruck at your magnificence!",lastmonst
);
927 if (mster
==BAT
) dam
=1;
930 dam
= monster
[mster
].damage
;
931 dam
+= rnd((int)((dam
<1)?1:dam
)) + monster
[mster
].level
;
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))
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(); }
944 if (tmp
== 0) lprintf("\n The %s missed ",lastmonst
);
948 * dropsomething(monst) Function to create an object when a monster dies
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.
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;
965 case LEPRECHAUN
: if (rnd(101)>=75) creategem();
966 if (rnd(5)==1) dropsomething(LEPRECHAUN
); return;
971 * dropgold(amount) Function to drop some gold around player
974 * Enter with the number of gold pieces to drop
975 * Returns nothing of value.
980 if (amount
> 250) createitem(OMAXGOLD
,amount
/100); else createitem(OGOLDPILE
,amount
);
984 * something(level) Function to create a random item around player
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.
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
);
1002 * newobject(lev,i) Routine to return a randomly selected new object
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
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
,
1017 register int lev
,*i
;
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 */
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;
1046 * spattack(atckno,xx,yy) Function to process special attacks from monsters
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
1053 * atckno monster effect
1054 * ---------------------------------------------------
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
1073 * char rustarm[ARMORTYPES][2];
1074 * special array for maximum rust damage to armor from rustmonster
1075 * format is: { armor type , minimum attribute
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 };
1084 register int i
,j
=0,k
,m
;
1086 if (c
[CANCELLATION
]) return(0);
1087 vxy(&xx
,&yy
); /* verify x & y coordinates */
1090 case 1: /* rust your armor, j=1 when rusting has occurred */
1092 if ((i
=c
[SHIELD
]) != -1)
1093 if (--ivenarg
[i
] < -1) ivenarg
[i
]= -1; else j
=1;
1094 if ((j
==0) && (k
!= -1))
1097 for (i
=0; i
<ARMORTYPES
; i
++)
1098 if (m
== rustarm
[i
][0]) /* find his armor in table */
1100 if (--ivenarg
[k
]< rustarm
[i
][1])
1101 ivenarg
[k
]= rustarm
[i
][1]; else j
=1;
1105 if (j
==0) /* if rusting did not occur */
1108 case OLEATHER
: p
= "\nThe %s hit you -- Your lucky you have leather on";
1110 case OSSPLATE
: p
= "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
1113 else { beep(); p
= "\nThe %s hit you -- your armor feels weaker"; }
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!";
1121 spout2
: if (p
) { lprintf(p
,lastmonst
); beep(); }
1125 case 3: i
= rnd(20)+25-c
[AC
]; goto spout
;
1127 case 4: if (c
[STRENGTH
]>3)
1129 p
="\nThe %s stung you! You feel weaker"; beep();
1132 else p
="\nThe %s stung you!";
1135 case 5: p
="\nThe %s blasts you with his cold breath";
1136 i
= rnd(15)+18-c
[AC
]; goto spout2
;
1138 case 6: lprintf("\nThe %s drains you of your life energy!",lastmonst
);
1139 loselevel(); beep(); return(0);
1141 case 7: p
="\nThe %s got you with a gusher!";
1142 i
= rnd(15)+25-c
[AC
]; goto spout2
;
1144 case 8: if (c
[NOTHEFT
]) return(0); /* he has a device of no theft */
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;
1152 else p
="\nThe %s couldn't find any gold to steal";
1153 lprintf(p
,lastmonst
); disappear(xx
,yy
); beep();
1154 bottomgold(); return(1);
1156 case 9: for(j
=50; ; ) /* disenchant */
1158 i
=rund(26); m
=iven
[i
]; /* randomly select item */
1159 if (m
>0 && ivenarg
[i
]>0 && m
!=OSCROLL
&& m
!=OPOTION
)
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);
1167 p
="\nThe %s nearly misses"; break;
1173 case 10: p
="\nThe %s hit you with his barbed tail";
1174 i
= rnd(25)-c
[AC
]; goto spout2
;
1176 case 11: p
="\nThe %s has confused you"; beep();
1177 c
[CONFUSE
]+= 10+rnd(10); break;
1179 case 12: /* performs any number of other special attacks */
1180 return(spattack(spsel
[rund(10)],xx
,yy
));
1182 case 13: p
="\nThe %s flattens you with his psionics!";
1183 i
= rnd(15)+30-c
[AC
]; goto spout2
;
1185 case 14: if (c
[NOTHEFT
]) return(0); /* he has device of no theft */
1186 if (emptyhanded()==1)
1188 p
="\nThe %s couldn't find anything to steal";
1191 lprintf("\nThe %s picks your pocket and takes:",lastmonst
);
1193 if (stealsomething()==0) lprcat(" nothing"); disappear(xx
,yy
);
1194 bottomline(); return(1);
1196 case 15: i
= rnd(10)+ 5-c
[AC
];
1197 spout3
: p
="\nThe %s bit you!";
1200 case 16: i
= rnd(15)+10-c
[AC
]; goto spout3
;
1202 if (p
) { lprintf(p
,lastmonst
); bottomline(); }
1207 * checkloss(x) Routine to subtract hp from user and flag bottomline display
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!
1217 if (x
>0) { losehp(x
); bottomhp(); }
1221 * annihilate() Routine to annihilate all monsters around player (playerx,playery)
1223 * Gives player experience, but no dropped objects
1224 * Returns the experience gained from all monsters killed
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 */
1237 k
+= monster
[*p
].experience
; *p
=know
[i
][j
]=0;
1241 lprintf("\nThe %s barely escapes being annihilated!",monster
[*p
].name
);
1242 hitp
[i
][j
] = (hitp
[i
][j
]>>1) + 1; /* lose half hit points*/
1246 lprcat("\nYou hear loud screams of agony!"); raiseexperience((long)k
);
1252 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
1253 * int x,y,dir,lifetime;
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
1260 newsphere(x
,y
,dir
,life
)
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 */
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;
1274 if ((m
=mitem
[x
][y
]) >= DEMONLORD
+4) /* demons dispel spheres */
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 */
1281 if (m
==DISENCHANTRESS
) /* disenchantress cancels spheres */
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 */
1288 if (c
[CANCELLATION
]) /* cancellation cancels spheres */
1290 cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
1293 if (item
[x
][y
]==OANNIHILATION
) /* collision of spheres detonates spheres */
1295 cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
1299 if (playerx
==x
&& playery
==y
) /* collision of sphere and player! */
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);
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 */
1312 sp
->p
= spheres
; spheres
= sp
;
1314 return(++c
[SPHCAST
]); /* one more sphere in the world */
1318 * rmsphere(x,y) Function to delete a sphere of annihilation from list
1321 * Enter with the coordinates of the sphere (on current level)
1322 * Returns the number of spheres currently in existence
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 */
1332 item
[x
][y
]=mitem
[x
][y
]=0; know
[x
][y
]=1;
1333 show1cell(x
,y
); /* show the now missing sphere */
1335 if (sp
==spheres
) { sp2
=sp
; spheres
=sp
->p
; free((char*)sp2
); }
1337 { sp2
->p
= sp
->p
; free((char*)sp
); }
1340 return(c
[SPHCAST
]); /* return number of spheres in the world */
1344 * sphboom(x,y) Function to perform the effects of a sphere detonation
1347 * Enter with the coordinates of the blast, Returns no value
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
++)
1358 item
[j
][i
]=mitem
[j
][i
]=0;
1360 if (playerx
==j
&& playery
==i
)
1363 lprcat("\nYou were too close to the sphere!");
1365 died(283); /* player killed in explosion */
1371 * genmonst() Function to ask for monster and genocide from game
1373 * This is done by setting a flag in the monster[] structure
1378 cursors(); lprcat("\nGenocide what monster? ");
1379 for (i
=0; (!isalpha(i
)) && (i
!=' '); i
=getchar());
1381 for (j
=0; j
<MAXMONST
; j
++) /* search for the monster type */
1382 if (monstnamelist
[j
]==i
) /* have we found it? */
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();
1390 lprcat(" You sense failure!");