]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/monster.c
2 * monster.c Larn is copyrighted 1986 by Noah Morgan.
4 * This file contains the following functions:
5 * ----------------------------------------------------------------------------
7 * createmonster(monstno) Function to create a monster next to the player
10 * int cgood(x,y,itm,monst) Function to check location for emptiness
13 * createitem(it,arg) Routine to place an item next to the player
16 * cast() Subroutine called by parse to cast a spell for the user
18 * speldamage(x) Function to perform spell functions cast by the player
21 * loseint() Routine to decrement your int (intelligence) if > 3
23 * isconfuse() Routine to check to see if player is confused
25 * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
28 * fullhit(xx) Function to return full damage against a monst (aka web)
31 * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
35 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
36 * int spnum,dam,delay;
39 * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
42 * tdirect(spnum) Routine to teleport away a monster
45 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
49 * dirsub(x,y) Routine to ask for direction, then modify x,y for it
52 * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds
55 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
58 * hitmonster(x,y) Function to hit a monster at the designated coordinates
61 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
64 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
67 * dropsomething(monst) Function to create an object when a monster dies
70 * dropgold(amount) Function to drop some gold around player
73 * something(level) Function to create a random item around player
76 * newobject(lev,i) Routine to return a randomly selected new object
79 * spattack(atckno,xx,yy) Function to process special attacks from monsters
82 * checkloss(x) Routine to subtract hp from user and flag bottomline display
85 * annihilate() Routine to annihilate monsters around player, playerx,playery
87 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
88 * int x,y,dir,lifetime;
90 * rmsphere(x,y) Function to delete a sphere of annihilation from list
93 * sphboom(x,y) Function to perform the effects of a sphere detonation
96 * genmonst() Function to ask for monster and genocide from game
101 struct isave
/* used for altar reality */
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 */
109 * createmonster(monstno) Function to create a monster next to the player
112 * Enter with the monster number (1 to MAXMONST+8)
118 register int x
,y
,k
,i
;
119 if (mon
<1 || mon
>MAXMONST
+8) /* check for monster number out of bounds */
121 beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon
); nap(3000); return;
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 */
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 */
131 hitp
[x
][y
] = monster
[mon
].hitpoints
;
132 stealth
[x
][y
]=know
[x
][y
]=0;
135 case ROTHE
: case POLTERGEIST
: case VAMPIRE
: stealth
[x
][y
]=1;
143 * int cgood(x,y,itm,monst) Function to check location for emptiness
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
153 int cgood(x
,y
,itm
,monst
)
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 */
167 * createitem(it,arg) Routine to place an item next to the player
170 * Enter with the item number and its argument (iven[], ivenarg[])
171 * Returns no value, thus we don't know about createitem() failures.
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 */
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 */
184 item
[x
][y
] = it
; know
[x
][y
]=0; iarg
[x
][y
]=arg
; return;
190 * cast() Subroutine called by parse to cast a spell for the user
192 * No arguments and no return value.
194 static char eys
[] = "\nEnter your spell: ";
197 register int i
,j
,a
,b
,d
;
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 */
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
))
213 { speldamage(i
); j
= 1; i
=SPNUM
; }
215 if (j
== -1) lprcat(" Nothing Happened ");
222 * speldamage(x) Function to perform spell functions cast by the player
225 * Enter with the spell number, returns no value.
226 * Please insure that there are 2 spaces before all messages here
231 register int i
,j
,clev
;
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 */
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; }
243 /* ----- LEVEL 1 SPELLS ----- */
245 case 0: if (c
[PROTECTIONTIME
]==0) c
[MOREDEFENSES
]+=2; /* protection field +2 */
246 c
[PROTECTIONTIME
] += 250; return;
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 */
253 case 2: if (c
[DEXCOUNT
]==0) c
[DEXTERITY
]+=3; /* dexterity */
254 c
[DEXCOUNT
] += 400; return;
257 p
=" While the %s slept, you smashed it %d times";
258 ws
: direct(x
,fullhit(i
),p
,i
); /* sleep */ return;
260 case 4: /* charm monster */ c
[CHARMCOUNT
] += c
[CHARISMA
]<<1; return;
262 case 5: godirect(x
,rnd(10)+15+clev
," The sound damages the %s",70,'@'); /* sonic spear */
265 /* ----- LEVEL 2 SPELLS ----- */
267 case 6: i
=rnd(3)+2; p
=" While the %s is entangled, you hit %d times";
270 case 7: if (c
[STRCOUNT
]==0) c
[STREXTRA
]+=3; /* strength */
271 c
[STRCOUNT
] += 150+rnd(100); return;
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;
280 case 9: raisehp(20+(clev
<<1)); return; /* healing */
282 case 10: c
[BLINDCOUNT
]=0; return; /* cure blindness */
284 case 11: createmonster(makemonst(level
+1)+8); return;
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!");
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;
295 /* ----- LEVEL 3 SPELLS ----- */
297 case 14: godirect(x
,rnd(25+clev
)+25+clev
," The fireball hits the %s",40,'*'); return; /* fireball */
299 case 15: godirect(x
,rnd(25)+20+clev
," Your cone of cold strikes the %s",60,'O'); /* cold */
302 case 16: dirpoly(x
); return; /* polymorph */
304 case 17: c
[CANCELLATION
]+= 5+clev
; return; /* cancellation */
306 case 18: c
[HASTESELF
]+= 7+clev
; return; /* haste self */
308 case 19: omnidirect(x
,30+rnd(10)," The %s gasps for air"); /* cloud kill */
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
++)
315 kn
= &know
[i
][j
]; pm
= &mitem
[i
][j
];
316 switch(*(p
= &item
[i
][j
]))
318 case OWALL
: if (level
< MAXLEVEL
+MAXVLEVEL
-1)
322 case OSTATUE
: if (c
[HARDGAME
]<3)
324 *p
=OBOOK
; iarg
[i
][j
]=level
; *kn
=0;
328 case OTHRONE
: *pm
=GNOMEKING
; *kn
=0; *p
= OTHRONE2
;
329 hitp
[i
][j
]=monster
[GNOMEKING
].hitpoints
; break;
331 case OALTAR
: *pm
=DEMONPRINCE
; *kn
=0;
332 hitp
[i
][j
]=monster
[DEMONPRINCE
].hitpoints
; break;
336 case XORN
: ifblind(i
,j
); hitm(i
,j
,200); break; /* Xorn takes damage from vpr */
341 /* ----- LEVEL 4 SPELLS ----- */
343 case 21: direct(x
,100+clev
," The %s shrivels up",0); /* dehydration */
346 case 22: godirect(x
,rnd(25)+20+(clev
<<1)," A lightning bolt hits the %s",1,'~'); /* lightning */
349 case 23: i
=min(c
[HP
]-1,c
[HPMAX
]/2); /* drain life */
350 direct(x
,i
+i
,"",0); c
[HP
] -= i
; return;
352 case 24: if (c
[GLOBE
]==0) c
[MOREDEFENSES
] += 10;
353 c
[GLOBE
] += 200; loseint(); /* globe of invulnerability */
356 case 25: omnidirect(x
,32+clev
," The %s struggles for air in your flood!"); /* flood */
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;
363 /* ----- LEVEL 5 SPELLS ----- */
365 case 27: c
[SCAREMONST
] += rnd(10)+clev
; return; /* scare monster */
367 case 28: c
[HOLDMONST
] += rnd(10)+clev
; return; /* hold monster */
369 case 29: c
[TIMESTOP
] += rnd(20)+(clev
<<1); return; /* time stop */
371 case 30: tdirect(x
); return; /* teleport away */
373 case 31: omnidirect(x
,35+rnd(10)+clev
," The %s cringes from the flame"); /* magic fire */
376 /* ----- LEVEL 6 SPELLS ----- */
378 case 32: if ((rnd(23)==5) && (wizard
==0)) /* sphere of annihilation */
380 beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
381 nap(4000); died(258); return;
383 xl
=playerx
; yl
=playery
;
385 i
=dirsub(&xl
,&yl
); /* get direction of sphere */
386 newsphere(xl
,yl
,i
,rnd(20)+11); /* make a sphere */
389 case 33: genmonst(); spelknow
[33]=0; /* genocide */
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;
400 case 35: /* walk through walls */
401 c
[WTW
] += rnd(10)+5; return;
403 case 36: /* alter reality */
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 */
412 if (xl
&& xl
!=OWALL
&& xl
!=OANNIHILATION
)
414 save
[sc
].type
=0; save
[sc
].id
=item
[i
][j
];
415 save
[sc
++].arg
=iarg
[i
][j
];
419 save
[sc
].type
=1; save
[sc
].id
=mitem
[i
][j
];
420 save
[sc
++].arg
=hitp
[i
][j
];
422 item
[i
][j
]=OWALL
; mitem
[i
][j
]=0;
423 if (wizard
) know
[i
][j
]=1; else know
[i
][j
]=0;
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 */
430 if (save
[sc
].type
== 0)
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
; }
437 { /* put monsters back in */
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
; }
444 draws(0,MAXX
,0,MAXY
); if (wizard
==0) spelknow
[36]=0;
445 free((char*)save
); positionplayer(); return;
448 case 37: /* permanence */ adjtime(-99999L); spelknow
[37]=0; /* forget */
452 default: lprintf(" spell %d not available!",(long)x
); beep(); return;
457 * loseint() Routine to subtract 1 from your int (intelligence) if > 3
459 * No arguments and no return value
463 if (--c
[INTELLIGENCE
]<3) c
[INTELLIGENCE
]=3;
467 * isconfuse() Routine to check to see if player is confused
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
474 if (c
[CONFUSE
]) { lprcat(" You can't aim your magic!"); beep(); }
479 * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
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.
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);
496 * fullhit(xx) Function to return full damage against a monster (aka web)
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
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
);
513 * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
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.
522 direct(spnum
,dam
,str
,arg
)
528 if (spnum
<0 || spnum
>=SPNUM
|| str
==0) return; /* bad arguments */
529 if (isconfuse()) return;
532 if (item
[x
][y
]==OMIRROR
)
534 if (spnum
==3) /* sleep */
536 lprcat("You fall asleep! "); beep();
539 while (arg
-- > 0) { parse2(); nap(1000); }
542 else if (spnum
==6) /* web */
544 lprcat("You get stuck in your own web! "); beep();
550 lprintf(str
,"spell caster (thats you)",(long)arg
);
551 beep(); losehp(dam
); return;
555 { lprcat(" There wasn't anything there!"); return; }
557 if (nospell(spnum
,m
)) { lasthx
=x
; lasthy
=y
; return; }
558 lprintf(str
,lastmonst
,(long)arg
); hitm(x
,y
,dam
);
562 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
563 * int spnum,dam,delay;
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.
573 godirect(spnum
,dam
,str
,delay
,cshow
)
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
;
587 if ((x
> MAXX
-1) || (y
> MAXY
-1) || (x
< 0) || (y
< 0))
589 dam
=0; break; /* out of bounds */
591 if ((x
==playerx
) && (y
==playery
)) /* if energy hits player */
593 cursors(); lprcat("\nYou are hit my your own magic!"); beep();
594 lastnum
=278; losehp(dam
); return;
596 if (c
[BLINDCOUNT
]==0) /* if not blind show effect */
598 cursor(x
+1,y
+1); lprc(cshow
); nap(delay
); show1cell(x
,y
);
600 if ((m
=mitem
[x
][y
])) /* is there a monster there? */
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
;
608 else switch (*(p
= &item
[x
][y
]))
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
))
615 lprcat(" The wall crumbles");
620 god2
: dam
= 0; break;
622 case OCLOSEDDOOR
: cursors(); lprc('\n'); lprintf(str
,"door");
625 lprcat(" The door is blasted apart");
630 case OSTATUE
: cursors(); lprc('\n'); lprintf(str
,"statue");
634 lprcat(" The statue crumbles");
635 *p
=OBOOK
; iarg
[x
][y
]=level
;
640 case OTHRONE
: cursors(); lprc('\n'); lprintf(str
,"throne");
643 mitem
[x
][y
]=GNOMEKING
; hitp
[x
][y
]=monster
[GNOMEKING
].hitpoints
;
649 case OMIRROR
: dx
*= -1; dy
*= -1; break;
651 dam
-= 3 + (c
[HARDGAME
]>>1);
656 * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
659 * Subroutine to copy the word "monster" into lastmonst if the player is blind
660 * Enter with the coordinates (x,y) of the monster
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
; }
674 * tdirect(spnum) Routine to teleport away a monster
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
686 if (spnum
<0 || spnum
>=SPNUM
) return; /* bad args */
687 if (isconfuse()) return;
689 if ((m
=mitem
[x
][y
])==0)
690 { lprcat(" There wasn't anything there!"); return; }
692 if (nospell(spnum
,m
)) { lasthx
=x
; lasthy
=y
; return; }
693 fillmonst(m
); mitem
[x
][y
]=know
[x
][y
]=0;
697 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
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.
706 omnidirect(spnum
,dam
,str
)
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
++)
716 if (nospell(spnum
,m
) == 0)
719 cursors(); lprc('\n'); lprintf(str
,lastmonst
);
720 hitm(x
,y
,dam
); nap(800);
722 else { lasthx
=x
; lasthy
=y
; }
727 * static dirsub(x,y) Routine to ask for direction, then modify x,y for it
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).
739 lprcat("\nIn What Direction? ");
750 case 'j': i
++; goto out
;
753 *x
= playerx
+diroffx
[i
]; *y
= playery
+diroffy
[i
];
758 * vxy(x,y) Routine to verify/fix coordinates for being within bounds
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.
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
++; }
779 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
782 * Subroutine to polymorph a monster and ask for the direction its in
783 * Enter with the spell number in spmun.
790 if (spnum
<0 || spnum
>=SPNUM
) return; /* bad args */
791 if (isconfuse()) return; /* if he is confused, he can't aim his magic */
794 { lprcat(" There wasn't anything there!"); return; }
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 */
803 * hitmonster(x,y) Function to hit a monster at the designated coordinates
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).
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;
820 if ((rnd(20) < tmp
-c
[HARDGAME
]) || (rnd(71) < 5)) /* need at least random chance to hit */
822 lprcat("\nYou hit"); flag
=1;
824 if (damag
<9999) damag
=rnd(damag
)+1;
828 lprcat("\nYou missed"); flag
=0;
830 lprcat(" the "); lprcat(lastmonst
);
831 if (flag
) /* if the monster was hit */
832 if ((monst
==RUSTMONSTER
) || (monst
==DISENCHANTRESS
) || (monst
==CUBE
))
834 if (ivenarg
[c
[WIELD
]] > -10)
836 lprintf("\nYour weapon is dulled by the %s",lastmonst
); beep();
839 if (flag
) hitm(x
,y
,damag
);
840 if (monst
== VAMPIRE
) if (hitp
[x
][y
]<25) { mitem
[x
][y
]=BAT
; know
[x
][y
]=0; }
844 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
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)
857 vxy(&x
,&y
); /* verify coordinates are within range */
858 amt2
= amt
; /* save initial damage so we can return it */
860 if (c
[HALFDAM
]) amt
>>= 1; /* if half damage curse adjust damage points */
861 if (amt
<=0) amt2
= amt
= 1;
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 */
867 case WHITEDRAGON
: case REDDRAGON
: case GREENDRAGON
:
868 case BRONZEDRAGON
: case PLATINUMDRAGON
: case SILVERDRAGON
:
869 amt
*= 1+(c
[SLAYING
]<<1); break;
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
)
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();
885 hitp
[x
][y
] = hpoints
-amt
; return(amt2
);
889 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
892 * Function for the monster to hit the player with monster at location x,y
893 * Returns nothing of value.
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)
907 know
[x
][y
]=1; show1cell(x
,y
);
909 bias
= (c
[HARDGAME
]) + 1;
910 hitflag
= hit2flag
= hit3flag
= 1;
912 cursors(); ifblind(x
,y
);
913 if (c
[INVISIBILITY
]) if (rnd(33)<20)
915 lprintf("\nThe %s misses wildly",lastmonst
); return;
917 if (c
[CHARMCOUNT
]) if (rnd(30)+5*monster
[mster
].level
-c
[CHARISMA
]<30)
919 lprintf("\nThe %s is awestruck at your magnificence!",lastmonst
);
922 if (mster
==BAT
) dam
=1;
925 dam
= monster
[mster
].damage
;
926 dam
+= rnd((int)((dam
<1)?1:dam
)) + monster
[mster
].level
;
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))
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(); }
939 if (tmp
== 0) lprintf("\n The %s missed ",lastmonst
);
943 * dropsomething(monst) Function to create an object when a monster dies
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.
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;
960 case LEPRECHAUN
: if (rnd(101)>=75) creategem();
961 if (rnd(5)==1) dropsomething(LEPRECHAUN
); return;
966 * dropgold(amount) Function to drop some gold around player
969 * Enter with the number of gold pieces to drop
970 * Returns nothing of value.
975 if (amount
> 250) createitem(OMAXGOLD
,amount
/100); else createitem(OGOLDPILE
,amount
);
979 * something(level) Function to create a random item around player
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.
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
);
997 * newobject(lev,i) Routine to return a randomly selected new object
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
1004 static 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
,
1012 register int lev
,*i
;
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 */
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;
1041 * spattack(atckno,xx,yy) Function to process special attacks from monsters
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
1048 * atckno monster effect
1049 * ---------------------------------------------------
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
1068 * char rustarm[ARMORTYPES][2];
1069 * special array for maximum rust damage to armor from rustmonster
1070 * format is: { armor type , minimum attribute
1072 #define ARMORTYPES 6
1073 static char rustarm
[ARMORTYPES
][2] = { OSTUDLEATHER
,-2, ORING
,-4, OCHAIN
,-5,
1074 OSPLINT
,-6, OPLATE
,-8, OPLATEARMOR
,-9 };
1075 static char spsel
[] = { 1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
1079 register int i
,j
=0,k
,m
;
1081 if (c
[CANCELLATION
]) return(0);
1082 vxy(&xx
,&yy
); /* verify x & y coordinates */
1085 case 1: /* rust your armor, j=1 when rusting has occurred */
1087 if ((i
=c
[SHIELD
]) != -1)
1088 if (--ivenarg
[i
] < -1) ivenarg
[i
]= -1; else j
=1;
1089 if ((j
==0) && (k
!= -1))
1092 for (i
=0; i
<ARMORTYPES
; i
++)
1093 if (m
== rustarm
[i
][0]) /* find his armor in table */
1095 if (--ivenarg
[k
]< rustarm
[i
][1])
1096 ivenarg
[k
]= rustarm
[i
][1]; else j
=1;
1100 if (j
==0) /* if rusting did not occur */
1103 case OLEATHER
: p
= "\nThe %s hit you -- Your lucky you have leather on";
1105 case OSSPLATE
: p
= "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
1108 else { beep(); p
= "\nThe %s hit you -- your armor feels weaker"; }
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!";
1116 spout2
: if (p
) { lprintf(p
,lastmonst
); beep(); }
1120 case 3: i
= rnd(20)+25-c
[AC
]; goto spout
;
1122 case 4: if (c
[STRENGTH
]>3)
1124 p
="\nThe %s stung you! You feel weaker"; beep();
1127 else p
="\nThe %s stung you!";
1130 case 5: p
="\nThe %s blasts you with his cold breath";
1131 i
= rnd(15)+18-c
[AC
]; goto spout2
;
1133 case 6: lprintf("\nThe %s drains you of your life energy!",lastmonst
);
1134 loselevel(); beep(); return(0);
1136 case 7: p
="\nThe %s got you with a gusher!";
1137 i
= rnd(15)+25-c
[AC
]; goto spout2
;
1139 case 8: if (c
[NOTHEFT
]) return(0); /* he has a device of no theft */
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;
1147 else p
="\nThe %s couldn't find any gold to steal";
1148 lprintf(p
,lastmonst
); disappear(xx
,yy
); beep();
1149 bottomgold(); return(1);
1151 case 9: for(j
=50; ; ) /* disenchant */
1153 i
=rund(26); m
=iven
[i
]; /* randomly select item */
1154 if (m
>0 && ivenarg
[i
]>0 && m
!=OSCROLL
&& m
!=OPOTION
)
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);
1162 p
="\nThe %s nearly misses"; break;
1168 case 10: p
="\nThe %s hit you with his barbed tail";
1169 i
= rnd(25)-c
[AC
]; goto spout2
;
1171 case 11: p
="\nThe %s has confused you"; beep();
1172 c
[CONFUSE
]+= 10+rnd(10); break;
1174 case 12: /* performs any number of other special attacks */
1175 return(spattack(spsel
[rund(10)],xx
,yy
));
1177 case 13: p
="\nThe %s flattens you with his psionics!";
1178 i
= rnd(15)+30-c
[AC
]; goto spout2
;
1180 case 14: if (c
[NOTHEFT
]) return(0); /* he has device of no theft */
1181 if (emptyhanded()==1)
1183 p
="\nThe %s couldn't find anything to steal";
1186 lprintf("\nThe %s picks your pocket and takes:",lastmonst
);
1188 if (stealsomething()==0) lprcat(" nothing"); disappear(xx
,yy
);
1189 bottomline(); return(1);
1191 case 15: i
= rnd(10)+ 5-c
[AC
];
1192 spout3
: p
="\nThe %s bit you!";
1195 case 16: i
= rnd(15)+10-c
[AC
]; goto spout3
;
1197 if (p
) { lprintf(p
,lastmonst
); bottomline(); }
1202 * checkloss(x) Routine to subtract hp from user and flag bottomline display
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!
1212 if (x
>0) { losehp(x
); bottomhp(); }
1216 * annihilate() Routine to annihilate all monsters around player (playerx,playery)
1218 * Gives player experience, but no dropped objects
1219 * Returns the experience gained from all monsters killed
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 */
1232 k
+= monster
[*p
].experience
; *p
=know
[i
][j
]=0;
1236 lprintf("\nThe %s barely escapes being annihilated!",monster
[*p
].name
);
1237 hitp
[i
][j
] = (hitp
[i
][j
]>>1) + 1; /* lose half hit points*/
1241 lprcat("\nYou hear loud screams of agony!"); raiseexperience((long)k
);
1247 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
1248 * int x,y,dir,lifetime;
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
1255 newsphere(x
,y
,dir
,life
)
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 */
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;
1269 if ((m
=mitem
[x
][y
]) >= DEMONLORD
+4) /* demons dispel spheres */
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 */
1276 if (m
==DISENCHANTRESS
) /* disenchantress cancels spheres */
1278 cursors(); lprintf("\nThe %s causes cancellation of the sphere!",monster
[m
].name
); beep();
1279 boom
: sphboom(x
,y
); /* blow up stuff around sphere */
1280 rmsphere(x
,y
); /* remove any spheres that are here */
1283 if (c
[CANCELLATION
]) /* cancellation cancels spheres */
1285 cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
1288 if (item
[x
][y
]==OANNIHILATION
) /* collision of spheres detonates spheres */
1290 cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
1294 if (playerx
==x
&& playery
==y
) /* collision of sphere and player! */
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);
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 */
1307 sp
->p
= spheres
; spheres
= sp
;
1309 return(++c
[SPHCAST
]); /* one more sphere in the world */
1313 * rmsphere(x,y) Function to delete a sphere of annihilation from list
1316 * Enter with the coordinates of the sphere (on current level)
1317 * Returns the number of spheres currently in existence
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 */
1327 item
[x
][y
]=mitem
[x
][y
]=0; know
[x
][y
]=1;
1328 show1cell(x
,y
); /* show the now missing sphere */
1330 if (sp
==spheres
) { sp2
=sp
; spheres
=sp
->p
; free((char*)sp2
); }
1332 { sp2
->p
= sp
->p
; free((char*)sp
); }
1335 return(c
[SPHCAST
]); /* return number of spheres in the world */
1339 * sphboom(x,y) Function to perform the effects of a sphere detonation
1342 * Enter with the coordinates of the blast, Returns no value
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
++)
1353 item
[j
][i
]=mitem
[j
][i
]=0;
1355 if (playerx
==j
&& playery
==i
)
1358 lprcat("\nYou were too close to the sphere!");
1360 died(283); /* player killed in explosion */
1366 * genmonst() Function to ask for monster and genocide from game
1368 * This is done by setting a flag in the monster[] structure
1373 cursors(); lprcat("\nGenocide what monster? ");
1374 for (i
=0; (!isalpha(i
)) && (i
!=' '); i
=getchar());
1376 for (j
=0; j
<MAXMONST
; j
++) /* search for the monster type */
1377 if (monstnamelist
[j
]==i
) /* have we found it? */
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();
1385 lprcat(" You sense failure!");