]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/monster.c
1 /* $NetBSD: monster.c,v 1.19 2019/02/03 03:19:25 mrg Exp $ */
4 * monster.c Larn is copyrighted 1986 by Noah Morgan.
6 * This file contains the following functions:
7 * ----------------------------------------------------------------------------
9 * createmonster(monstno) Function to create a monster next to the player
12 * int cgood(x,y,itm,monst)Function to check location for emptiness
15 * createitem(it,arg) Routine to place an item next to the player
18 * cast() Subroutine called by parse to cast a spell for the user
20 * speldamage(x) Function to perform spell functions cast by the player
23 * loseint() Routine to decrement your int (intelligence) if > 3
25 * isconfuse() Routine to check to see if player is confused
27 * nospell(x,monst)Routine to return 1 if a spell doesn't affect a monster
30 * fullhit(xx) Function to return full damage against a monst (aka web)
33 * direct(spnum,dam,str,arg)Routine to direct spell damage 1 square in 1 dir
37 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
38 * int spnum,dam,delay;
41 * ifblind(x,y)Routine to put "monster" or the monster name into lastmosnt
44 * tdirect(spnum) Routine to teleport away a monster
47 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
51 * dirsub(x,y) Routine to ask for direction, then modify x,y for it
54 * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds
57 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
60 * hitmonster(x,y) Function to hit a monster at the designated coordinates
63 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
66 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
69 * dropsomething(monst) Function to create an object when a monster dies
72 * dropgold(amount) Function to drop some gold around player
75 * something(level) Function to create a random item around player
78 * newobject(lev,i) Routine to return a randomly selected new object
81 * spattack(atckno,xx,yy) Function to process special attacks from monsters
84 * checkloss(x) Routine to subtract hp from user and flag bottomline display
87 * annihilate() Routine to annihilate monsters around player, playerx,playery
89 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
90 * int x,y,dir,lifetime;
92 * rmsphere(x,y) Function to delete a sphere of annihilation from list
95 * sphboom(x,y) Function to perform the effects of a sphere detonation
98 * genmonst() Function to ask for monster and genocide from game
101 #include <sys/cdefs.h>
103 __RCSID("$NetBSD: monster.c,v 1.19 2019/02/03 03:19:25 mrg Exp $");
104 #endif /* not lint */
112 struct isave
{ /* used for altar reality */
113 char type
; /* 0=item, 1=monster */
114 char id
; /* item number or monster number */
115 short arg
; /* the type of item or hitpoints of monster */
118 static int cgood(int, int, int, int);
119 static void speldamage(int);
120 static void loseint(void);
121 static int isconfuse(void);
122 static int nospell(int, int);
123 static int fullhit(int);
124 static void direct(int, int, const char *, int);
125 static void ifblind(int, int);
126 static void tdirect(int);
127 static void omnidirect(int, int, const char *);
128 static int dirsub(int *, int *);
129 static void dirpoly(int);
130 static int hitm(int, int, int);
131 static void dropsomething(int);
132 static int spattack(int, int, int);
133 static void sphboom(int, int);
134 static void genmonst(void);
137 * createmonster(monstno) Function to create a monster next to the player
140 * Enter with the monster number (1 to MAXMONST+8)
144 createmonster(int mon
)
147 if (mon
< 1 || mon
> MAXMONST
+ 8) { /* check for monster number
150 lprintf("\ncan't createmonst(%ld)\n", (long) mon
);
154 while (monster
[mon
].genocided
&& mon
< MAXMONST
)
155 mon
++; /* genocided? */
156 for (k
= rnd(8), i
= -8; i
< 0; i
++, k
++) { /* choose direction,
159 k
= 1; /* wraparound the diroff arrays */
160 x
= playerx
+ diroffx
[k
];
161 y
= playery
+ diroffy
[k
];
162 if (cgood(x
, y
, 0, 1)) { /* if we can create here */
164 hitp
[x
][y
] = monster
[mon
].hitpoints
;
165 stealth
[x
][y
] = know
[x
][y
] = 0;
178 * int cgood(x,y,itm,monst) Function to check location for emptiness
181 * Routine to return TRUE if a location does not have itm or monst there
182 * returns FALSE (0) otherwise
183 * Enter with itm or monst TRUE or FALSE if checking it
184 * Example: if itm==TRUE check for no item at this location
185 * if monst==TRUE check for no monster at this location
186 * This routine will return FALSE if at a wall or the dungeon exit on level 1
189 cgood(int x
, int y
, int theitem
, int monst
)
192 if ((y
>= 0) && (y
<= MAXY
- 1) && (x
>= 0) && (x
<= MAXX
- 1))
194 if (item
[x
][y
] != OWALL
) /* can't make anything on walls */
195 /* is it free of items? */
196 if (theitem
== 0 || (item
[x
][y
] == 0))
197 /* is it free of monsters? */
198 if (monst
== 0 || (mitem
[x
][y
] == 0))
199 if ((level
!= 1) || (x
!= 33) ||
201 /* not exit to level 1 */
207 * createitem(it,arg) Routine to place an item next to the player
210 * Enter with the item number and its argument (iven[], ivenarg[])
211 * Returns no value, thus we don't know about createitem() failures.
214 createitem(int it
, int arg
)
218 return; /* no such object */
219 for (k
= rnd(8), i
= -8; i
< 0; i
++, k
++) { /* choose direction,
222 k
= 1; /* wraparound the diroff arrays */
223 x
= playerx
+ diroffx
[k
];
224 y
= playery
+ diroffy
[k
];
225 if (cgood(x
, y
, 1, 0)) { /* if we can create here */
235 * cast() Subroutine called by parse to cast a spell for the user
237 * No arguments and no return value.
239 static char eys
[] = "\nEnter your spell: ";
245 if (c
[SPELLS
] <= 0) {
246 lprcat("\nYou don't have any spells!");
251 while ((a
= ttgetch()) == 'D') {
257 goto over
; /* to escape casting a spell */
258 if ((b
= ttgetch()) == '\33')
259 goto over
; /* to escape casting a spell */
260 if ((d
= ttgetch()) == '\33') {
261 over
: lprcat(aborted
);
264 } /* to escape casting a spell */
268 for (lprc('\n'), j
= -1, i
= 0; i
< SPNUM
; i
++) /* seq search for his
270 if ((spelcode
[i
][0] == a
) && (spelcode
[i
][1] == b
) && (spelcode
[i
][2] == d
))
277 lprcat(" Nothing Happened ");
282 * speldamage(x) Function to perform spell functions cast by the player
285 * Enter with the spell number, returns no value.
286 * Please insure that there are 2 spaces before all messages here
296 return; /* no such spell */
298 lprcat(" It didn't seem to work");
300 } /* not if time stopped */
302 if ((rnd(23) == 7) || (rnd(18) > c
[INTELLIGENCE
])) {
303 lprcat(" It didn't work!");
306 if (clev
* 3 + 2 < x
) {
307 lprcat(" Nothing happens. You seem inexperienced at this");
311 /* ----- LEVEL 1 SPELLS ----- */
314 if (c
[PROTECTIONTIME
] == 0)
315 c
[MOREDEFENSES
] += 2; /* protection field +2 */
316 c
[PROTECTIONTIME
] += 250;
320 i
= rnd(((clev
+ 1) << 1)) + clev
+ 3;
321 godirect(x
, i
, (clev
>= 2) ? " Your missiles hit the %s" : " Your missile hit the %s", 100, '+'); /* magic missile */
326 if (c
[DEXCOUNT
] == 0)
327 c
[DEXTERITY
] += 3; /* dexterity */
333 direct(x
, fullhit(i
),
334 " While the %s slept, you smashed it %ld times", i
);
337 case 4: /* charm monster */
338 c
[CHARMCOUNT
] += c
[CHARISMA
] << 1;
342 godirect(x
, rnd(10) + 15 + clev
, " The sound damages the %s", 70, '@'); /* sonic spear */
345 /* ----- LEVEL 2 SPELLS ----- */
349 direct(x
, fullhit(i
),
350 " While the %s is entangled, you hit %ld times", i
);
354 if (c
[STRCOUNT
] == 0)
355 c
[STREXTRA
] += 3; /* strength */
356 c
[STRCOUNT
] += 150 + rnd(100);
360 yl
= playery
- 5; /* enlightenment */
365 vxy(&xh
, &yh
); /* check bounds */
366 for (i
= yl
; i
<= yh
; i
++) /* enlightenment */
367 for (j
= xl
; j
<= xh
; j
++)
369 draws(xl
, xh
+ 1, yl
, yh
+ 1);
373 raisehp(20 + (clev
<< 1));
374 return; /* healing */
378 return; /* cure blindness */
381 createmonster(makemonst(level
+ 1) + 8);
385 if (rnd(11) + 7 <= c
[WISDOM
])
386 direct(x
, rnd(20) + 20 + clev
, " The %s believed!", 0);
388 lprcat(" It didn't believe the illusions!");
391 case 13: /* if he has the amulet of invisibility then
393 for (j
= i
= 0; i
< 26; i
++)
394 if (iven
[i
] == OAMULET
)
396 c
[INVISIBILITY
] += (j
<< 7) + 12;
399 /* ----- LEVEL 3 SPELLS ----- */
402 godirect(x
, rnd(25 + clev
) + 25 + clev
, " The fireball hits the %s", 40, '*');
403 return; /* fireball */
406 godirect(x
, rnd(25) + 20 + clev
, " Your cone of cold strikes the %s", 60, 'O'); /* cold */
411 return; /* polymorph */
414 c
[CANCELLATION
] += 5 + clev
;
415 return; /* cancellation */
418 c
[HASTESELF
] += 7 + clev
;
419 return; /* haste self */
422 omnidirect(x
, 30 + rnd(10), " The %s gasps for air"); /* cloud kill */
426 xh
= min(playerx
+ 1, MAXX
- 2);
427 yh
= min(playery
+ 1, MAXY
- 2);
428 for (i
= max(playerx
- 1, 1); i
<= xh
; i
++) /* vaporize rock */
429 for (j
= max(playery
- 1, 1); j
<= yh
; j
++) {
432 switch (*(p
= &item
[i
][j
])) {
434 if (level
< MAXLEVEL
+ MAXVLEVEL
- 1)
439 if (c
[HARDGAME
] < 3) {
450 hitp
[i
][j
] = monster
[GNOMEKING
].hitpoints
;
456 hitp
[i
][j
] = monster
[DEMONPRINCE
].hitpoints
;
463 break; /* Xorn takes damage from vpr */
468 /* ----- LEVEL 4 SPELLS ----- */
471 direct(x
, 100 + clev
, " The %s shrivels up", 0); /* dehydration */
475 godirect(x
, rnd(25) + 20 + (clev
<< 1), " A lightning bolt hits the %s", 1, '~'); /* lightning */
479 i
= min(c
[HP
] - 1, c
[HPMAX
] / 2); /* drain life */
480 direct(x
, i
+ i
, "", 0);
486 c
[MOREDEFENSES
] += 10;
488 loseint(); /* globe of invulnerability */
492 omnidirect(x
, 32 + clev
, " The %s struggles for air in your flood!"); /* flood */
496 if (rnd(151) == 63) {
498 lprcat("\nYour heart stopped!\n");
503 if (c
[WISDOM
] > rnd(10) + 10)
504 direct(x
, 2000, " The %s's heart stopped", 0); /* finger of death */
506 lprcat(" It didn't work");
509 /* ----- LEVEL 5 SPELLS ----- */
512 c
[SCAREMONST
] += rnd(10) + clev
;
513 return; /* scare monster */
516 c
[HOLDMONST
] += rnd(10) + clev
;
517 return; /* hold monster */
520 c
[TIMESTOP
] += rnd(20) + (clev
<< 1);
521 return; /* time stop */
525 return; /* teleport away */
528 omnidirect(x
, 35 + rnd(10) + clev
, " The %s cringes from the flame"); /* magic fire */
531 /* ----- LEVEL 6 SPELLS ----- */
534 if ((rnd(23) == 5) && (wizard
== 0)) { /* sphere of
537 lprcat("\nYou have been enveloped by the zone of nothingness!\n");
545 i
= dirsub(&xl
, &yl
); /* get direction of sphere */
546 newsphere(xl
, yl
, i
, rnd(20) + 11); /* make a sphere */
551 spelknow
[33] = 0; /* genocide */
555 case 34: /* summon demon */
557 direct(x
, 150, " The demon strikes at the %s", 0);
561 lprcat(" Nothing seems to have happened");
564 lprcat(" The demon turned on you and vanished!");
568 losehp(i
); /* must say killed by a demon */
571 case 35: /* walk through walls */
572 c
[WTW
] += rnd(10) + 5;
575 case 36: /* alter reality */
577 struct isave
*save
; /* pointer to item save
580 sc
= 0; /* # items saved */
581 save
= (struct isave
*) malloc(sizeof(struct isave
) * MAXX
* MAXY
* 2);
582 for (j
= 0; j
< MAXY
; j
++)
583 for (i
= 0; i
< MAXX
; i
++) { /* save all items and
586 if (xl
&& xl
!= OWALL
&& xl
!= OANNIHILATION
) {
588 save
[sc
].id
= item
[i
][j
];
589 save
[sc
++].arg
= iarg
[i
][j
];
593 save
[sc
].id
= mitem
[i
][j
];
594 save
[sc
++].arg
= hitp
[i
][j
];
605 item
[33][MAXY
- 1] = 0;
606 for (j
= rnd(MAXY
- 2), i
= 1; i
< MAXX
- 1; i
++)
608 while (sc
> 0) { /* put objects back in level */
610 if (save
[sc
].type
== 0) {
612 for (trys
= 100, i
= j
= 1; --trys
> 0 && item
[i
][j
]; i
= rnd(MAXX
- 1), j
= rnd(MAXY
- 1));
614 item
[i
][j
] = save
[sc
].id
;
615 iarg
[i
][j
] = save
[sc
].arg
;
617 } else { /* put monsters back in */
619 for (trys
= 100, i
= j
= 1; --trys
> 0 && (item
[i
][j
] == OWALL
|| mitem
[i
][j
]); i
= rnd(MAXX
- 1), j
= rnd(MAXY
- 1));
621 mitem
[i
][j
] = save
[sc
].id
;
622 hitp
[i
][j
] = save
[sc
].arg
;
627 draws(0, MAXX
, 0, MAXY
);
635 case 37: /* permanence */
637 spelknow
[37] = 0; /* forget */
642 lprintf(" spell %ld not available!", (long) x
);
649 * loseint() Routine to subtract 1 from your int (intelligence) if > 3
651 * No arguments and no return value
656 if (--c
[INTELLIGENCE
] < 3)
661 * isconfuse() Routine to check to see if player is confused
663 * This routine prints out a message saying "You can't aim your magic!"
664 * returns 0 if not confused, non-zero (time remaining confused) if confused
670 lprcat(" You can't aim your magic!");
677 * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
680 * Subroutine to return 1 if the spell can't affect the monster
681 * otherwise returns 0
682 * Enter with the spell number in x, and the monster number in monst.
685 nospell(int x
, int monst
)
688 if (x
>= SPNUM
|| monst
>= MAXMONST
+ 8 || monst
< 0 || x
< 0)
689 return (0); /* bad spell or monst */
690 if ((tmp
= spelweird
[monst
- 1][x
]) == 0)
694 lprintf(spelmes
[tmp
], monster
[monst
].name
);
699 * fullhit(xx) Function to return full damage against a monster (aka web)
702 * Function to return hp damage to monster due to a number of full hits
703 * Enter with the number of full hits being done
709 if (xx
< 0 || xx
> 20)
710 return (0); /* fullhits are out of range */
712 return (10000); /* lance of death */
713 i
= xx
* ((c
[WCLASS
] >> 1) + c
[STRENGTH
] + c
[STREXTRA
] - c
[HARDGAME
] - 12 + c
[MOREDAM
]);
714 return ((i
>= 1) ? i
: xx
);
718 * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
722 * Routine to ask for a direction to a spell and then hit the monster
723 * Enter with the spell number in spnum, the damage to be done in dam,
724 * lprintf format string in str, and lprintf's argument in arg.
728 direct(int spnum
, int dam
, const char *str
, int arg
)
732 if (spnum
< 0 || spnum
>= SPNUM
|| str
== 0)
733 return; /* bad arguments */
738 if (item
[x
][y
] == OMIRROR
) {
739 if (spnum
== 3) { /* sleep */
740 lprcat("You fall asleep! ");
749 } else if (spnum
== 6) { /* web */
750 lprcat("You get stuck in your own web! ");
755 lprintf(str
, "spell caster (that's you)", (long) arg
);
762 lprcat(" There wasn't anything there!");
766 if (nospell(spnum
, m
)) {
771 lprintf(str
, lastmonst
, (long) arg
);
776 * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
777 * int spnum,dam,delay;
780 * Function to hit in a direction from a missile weapon and have it keep
781 * on going in that direction until its power is exhausted
782 * Enter with the spell number in spnum, the power of the weapon in hp,
783 * lprintf format string in str, the # of milliseconds to delay between
784 * locations in delay, and the character to represent the weapon in cshow.
788 godirect(int spnum
, int dam
, const char *str
, int delay
, int cshow_i
)
795 /* truncate to char width in case it matters */
796 cshow
= (char)cshow_i
;
798 if (spnum
< 0 || spnum
>= SPNUM
|| str
== 0 || delay
< 0)
799 return; /* bad args */
812 if ((x
> MAXX
- 1) || (y
> MAXY
- 1) || (x
< 0) || (y
< 0)) {
814 break; /* out of bounds */
816 if ((x
== playerx
) && (y
== playery
)) { /* if energy hits player */
818 lprcat("\nYou are hit by your own magic!");
824 if (c
[BLINDCOUNT
] == 0) { /* if not blind show effect */
825 cursor(x
+ 1, y
+ 1);
830 if ((m
= mitem
[x
][y
])) { /* is there a monster there? */
832 if (nospell(spnum
, m
)) {
839 lprintf(str
, lastmonst
);
840 dam
-= hitm(x
, y
, dam
);
846 switch (*(p
= &item
[x
][y
])) {
850 lprintf(str
, "wall");
851 if (dam
>= 50 + c
[HARDGAME
]) /* enough damage? */
852 if (level
< MAXLEVEL
+ MAXVLEVEL
- 1) /* not on V3 */
853 if ((x
< MAXX
- 1) && (y
< MAXY
- 1) && (x
) && (y
)) {
854 lprcat(" The wall crumbles");
865 lprintf(str
, "door");
867 lprcat(" The door is blasted apart");
875 lprintf(str
, "statue");
878 lprcat(" The statue crumbles");
888 lprintf(str
, "throne");
890 mitem
[x
][y
] = GNOMEKING
;
891 hitp
[x
][y
] = monster
[GNOMEKING
].hitpoints
;
902 dam
-= 3 + (c
[HARDGAME
] >> 1);
907 * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
910 * Subroutine to copy the word "monster" into lastmonst if the player is blind
911 * Enter with the coordinates (x,y) of the monster
915 ifblind(int x
, int y
)
919 vxy(&x
, &y
); /* verify correct x,y coordinates */
924 lastnum
= mitem
[x
][y
];
925 p
= monster
[lastnum
].name
;
927 strcpy(lastmonst
, p
);
931 * tdirect(spnum) Routine to teleport away a monster
934 * Routine to ask for a direction to a spell and then teleport away monster
935 * Enter with the spell number that wants to teleport away
943 if (spnum
< 0 || spnum
>= SPNUM
)
944 return; /* bad args */
948 if ((m
= mitem
[x
][y
]) == 0) {
949 lprcat(" There wasn't anything there!");
953 if (nospell(spnum
, m
)) {
959 mitem
[x
][y
] = know
[x
][y
] = 0;
963 * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
967 * Routine to cast a spell and then hit the monster in all directions
968 * Enter with the spell number in sp, the damage done to wach square in dam,
969 * and the lprintf string to identify the spell in str.
973 omnidirect(int spnum
, int dam
, const char *str
)
977 if (spnum
< 0 || spnum
>= SPNUM
|| str
== 0)
978 return; /* bad args */
979 for (x
= playerx
- 1; x
< playerx
+ 2; x
++)
980 for (y
= playery
- 1; y
< playery
+ 2; y
++) {
981 if ((m
= mitem
[x
][y
]) != 0) {
982 if (nospell(spnum
, m
) == 0) {
986 lprintf(str
, lastmonst
);
998 * static dirsub(x,y) Routine to ask for direction, then modify x,y for it
1001 * Function to ask for a direction and modify an x,y for that direction
1002 * Enter with the origination coordinates in (x,y).
1003 * Returns index into diroffx[] (0-8).
1006 dirsub(int *x
, int *y
)
1009 lprcat("\nIn What Direction? ");
1011 switch (ttgetch()) {
1039 *x
= playerx
+ diroffx
[i
];
1040 *y
= playery
+ diroffy
[i
];
1046 * vxy(x,y) Routine to verify/fix coordinates for being within bounds
1049 * Function to verify x & y are within the bounds for a level
1050 * If *x or *y is not within the absolute bounds for a level, fix them so that
1051 * they are on the level.
1052 * Returns TRUE if it was out of bounds, and the *x & *y in the calling
1053 * routine are affected.
1079 * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
1082 * Subroutine to polymorph a monster and ask for the direction its in
1083 * Enter with the spell number in spmun.
1090 if (spnum
< 0 || spnum
>= SPNUM
)
1091 return; /* bad args */
1093 return; /* if he is confused, he can't aim his magic */
1095 if (mitem
[x
][y
] == 0) {
1096 lprcat(" There wasn't anything there!");
1100 if (nospell(spnum
, mitem
[x
][y
])) {
1105 while (monster
[m
= mitem
[x
][y
] = rnd(MAXMONST
+ 7)].genocided
);
1106 hitp
[x
][y
] = monster
[m
].hitpoints
;
1107 show1cell(x
, y
); /* show the new monster */
1111 * hitmonster(x,y) Function to hit a monster at the designated coordinates
1114 * This routine is used for a bash & slash type attack on a monster
1115 * Enter with the coordinates of the monster in (x,y).
1119 hitmonster(int x
, int y
)
1121 int tmp
, monst
, damag
= 0, flag
;
1123 return; /* not if time stopped */
1124 vxy(&x
, &y
); /* verify coordinates are within range */
1125 if ((monst
= mitem
[x
][y
]) == 0)
1129 tmp
= monster
[monst
].armorclass
+ c
[LEVEL
] + c
[DEXTERITY
] +
1132 /* need at least random chance to hit */
1133 if ((rnd(20) < tmp
- c
[HARDGAME
]) || (rnd(71) < 5)) {
1134 lprcat("\nYou hit");
1138 damag
= rnd(damag
) + 1;
1140 lprcat("\nYou missed");
1145 if (flag
) /* if the monster was hit */
1146 if ((monst
== RUSTMONSTER
) || (monst
== DISENCHANTRESS
) || (monst
== CUBE
))
1148 if (ivenarg
[c
[WIELD
]] > -10) {
1149 lprintf("\nYour weapon is dulled by the %s", lastmonst
);
1151 --ivenarg
[c
[WIELD
]];
1155 if (monst
== VAMPIRE
)
1156 if (hitp
[x
][y
] < 25) {
1163 * hitm(x,y,amt) Function to just hit a monster at a given coordinates
1166 * Returns the number of hitpoints the monster absorbed
1167 * This routine is used to specifically damage a monster at a location (x,y)
1168 * Called by hitmonster(x,y)
1171 hitm(int x
, int y
, int amt
)
1175 vxy(&x
, &y
); /* verify coordinates are within range */
1176 amt2
= amt
; /* save initial damage so we can return it */
1177 monst
= mitem
[x
][y
];
1179 amt
>>= 1; /* if half damage curse adjust damage points */
1184 stealth
[x
][y
] = 1; /* make sure hitting monst breaks stealth
1186 c
[HOLDMONST
] = 0; /* hit a monster breaks hold monster spell */
1187 switch (monst
) { /* if a dragon and orb(s) of dragon slaying */
1192 case PLATINUMDRAGON
:
1194 amt
*= 1 + (c
[SLAYING
] << 1);
1197 /* invincible monster fix is here */
1198 if (hitp
[x
][y
] > monster
[monst
].hitpoints
)
1199 hitp
[x
][y
] = monster
[monst
].hitpoints
;
1200 if ((hpoints
= hitp
[x
][y
]) <= amt
) {
1204 lprintf("\nThe %s died!", lastmonst
);
1205 raiseexperience((long) monster
[monst
].experience
);
1206 amt
= monster
[monst
].gold
;
1208 dropgold(rnd(amt
) + amt
);
1209 dropsomething(monst
);
1214 hitp
[x
][y
] = hpoints
- amt
;
1219 * hitplayer(x,y) Function for the monster to hit the player from (x,y)
1222 * Function for the monster to hit the player with monster at location x,y
1223 * Returns nothing of value.
1226 hitplayer(int x
, int y
)
1228 int dam
, tmp
, mster
, bias
;
1229 vxy(&x
, &y
); /* verify coordinates are within range */
1230 lastnum
= mster
= mitem
[x
][y
];
1232 * spirit nagas and poltergeists do nothing if scarab of negate
1235 if (c
[NEGATESPIRIT
] || c
[SPIRITPRO
])
1236 if ((mster
== POLTERGEIST
) || (mster
== SPIRITNAGA
))
1238 /* if undead and cube of undead control */
1239 if (c
[CUBEofUNDEAD
] || c
[UNDEADPRO
])
1240 if ((mster
== VAMPIRE
) || (mster
== WRAITH
) || (mster
== ZOMBIE
))
1242 if ((know
[x
][y
] & 1) == 0) {
1246 bias
= (c
[HARDGAME
]) + 1;
1247 hitflag
= hit2flag
= hit3flag
= 1;
1251 if (c
[INVISIBILITY
])
1253 lprintf("\nThe %s misses wildly", lastmonst
);
1257 if (rnd(30) + 5 * monster
[mster
].level
- c
[CHARISMA
] < 30) {
1258 lprintf("\nThe %s is awestruck at your magnificence!", lastmonst
);
1264 dam
= monster
[mster
].damage
;
1265 dam
+= rnd((int) ((dam
< 1) ? 1 : dam
)) + monster
[mster
].level
;
1268 if (monster
[mster
].attack
> 0)
1269 if (((dam
+ bias
+ 8) > c
[AC
]) || (rnd((int) ((c
[AC
] > 0) ? c
[AC
] : 1)) == 1)) {
1270 if (spattack(monster
[mster
].attack
, x
, y
)) {
1278 if (((dam
+ bias
) > c
[AC
]) || (rnd((int) ((c
[AC
] > 0) ? c
[AC
] : 1)) == 1)) {
1279 lprintf("\n The %s hit you ", lastmonst
);
1281 if ((dam
-= c
[AC
]) < 0)
1290 lprintf("\n The %s missed ", lastmonst
);
1294 * dropsomething(monst) Function to create an object when a monster dies
1297 * Function to create an object near the player when certain monsters are killed
1298 * Enter with the monster number
1299 * Returns nothing of value.
1302 dropsomething(int monst
)
1312 case PLATINUMDRAGON
:
1322 dropsomething(LEPRECHAUN
);
1328 * dropgold(amount) Function to drop some gold around player
1331 * Enter with the number of gold pieces to drop
1332 * Returns nothing of value.
1335 dropgold(int amount
)
1338 createitem(OMAXGOLD
, amount
/ 100);
1340 createitem(OGOLDPILE
, amount
);
1344 * something(level) Function to create a random item around player
1347 * Function to create an item from a designed probability around player
1348 * Enter with the cave level on which something is to be dropped
1349 * Returns nothing of value.
1352 something(int cavelevel
)
1356 if (cavelevel
< 0 || cavelevel
> MAXLEVEL
+ MAXVLEVEL
)
1357 return; /* correct level? */
1359 something(cavelevel
); /* possibly more than one item */
1360 j
= newobject(cavelevel
, &i
);
1365 * newobject(lev,i) Routine to return a randomly selected new object
1368 * Routine to return a randomly selected object to be created
1369 * Returns the object number created, and sets *i for its argument
1370 * Enter with the cave level and a pointer to the items arg
1372 static char nobjtab
[] = {
1373 0, OSCROLL
, OSCROLL
, OSCROLL
, OSCROLL
, OPOTION
, OPOTION
,
1374 OPOTION
, OPOTION
, OGOLDPILE
, OGOLDPILE
, OGOLDPILE
, OGOLDPILE
,
1375 OBOOK
, OBOOK
, OBOOK
, OBOOK
, ODAGGER
, ODAGGER
, ODAGGER
,
1376 OLEATHER
, OLEATHER
, OLEATHER
, OREGENRING
, OPROTRING
,
1377 OENERGYRING
, ODEXRING
, OSTRRING
, OSPEAR
, OBELT
, ORING
,
1378 OSTUDLEATHER
, OSHIELD
, OFLAIL
, OCHAIN
, O2SWORD
, OPLATE
,
1382 newobject(int lev
, int *i
)
1385 if (level
< 0 || level
> MAXLEVEL
+ MAXVLEVEL
)
1386 return (0); /* correct level? */
1391 j
= nobjtab
[tmp
= rnd(tmp
)]; /* the object type */
1409 *i
= rnd((lev
+ 1) * 10) + lev
* 10 + 10;
1420 if (!(*i
= newdagger()))
1426 if (!(*i
= newleather()))
1432 *i
= rund(lev
/ 3 + 1);
1436 *i
= rnd(lev
/ 4 + 1);
1439 *i
= rund(lev
/ 4 + 1);
1442 *i
= rnd(lev
/ 2 + 1);
1446 *i
= rund(lev
/ 2 + 1);
1449 *i
= rund(lev
/ 3 + 1);
1455 *i
= rund(lev
/ 2 + 1);
1473 * spattack(atckno,xx,yy) Function to process special attacks from monsters
1476 * Enter with the special attack number, and the coordinates (xx,yy)
1477 * of the monster that is special attacking
1478 * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
1480 * atckno monster effect
1481 * ---------------------------------------------------
1483 * 1 rust monster eat armor
1484 * 2 hell hound breathe light fire
1485 * 3 dragon breathe fire
1486 * 4 giant centipede weakening sing
1487 * 5 white dragon cold breath
1488 * 6 wraith drain level
1489 * 7 waterlord water gusher
1490 * 8 leprechaun steal gold
1491 * 9 disenchantress disenchant weapon or armor
1492 * 10 ice lizard hits with barbed tail
1493 * 11 umber hulk confusion
1494 * 12 spirit naga cast spells taken from special attacks
1495 * 13 platinum dragon psionics
1496 * 14 nymph steal objects
1500 * char rustarm[ARMORTYPES][2];
1501 * special array for maximum rust damage to armor from rustmonster
1502 * format is: { armor type , minimum attribute
1504 #define ARMORTYPES 6
1505 static char rustarm
[ARMORTYPES
][2] = {
1506 { OSTUDLEATHER
, -2 },
1513 static char spsel
[] = {1, 2, 3, 5, 6, 8, 9, 11, 13, 14};
1515 spattack(int x
, int xx
, int yy
)
1518 const char *p
= NULL
;
1520 if (c
[CANCELLATION
])
1522 vxy(&xx
, &yy
); /* verify x & y coordinates */
1524 case 1: /* rust your armor, j=1 when rusting has occurred */
1526 if ((i
= c
[SHIELD
]) != -1) {
1527 if (--ivenarg
[i
] < -1)
1532 if ((j
== 0) && (k
!= -1)) {
1534 for (i
= 0; i
< ARMORTYPES
; i
++)
1535 /* find his armor in table */
1536 if (m
== rustarm
[i
][0]) {
1537 if (--ivenarg
[k
] < rustarm
[i
][1])
1538 ivenarg
[k
] = rustarm
[i
][1];
1544 if (j
== 0) /* if rusting did not occur */
1547 p
= "\nThe %s hit you -- You're lucky you have leather on";
1550 p
= "\nThe %s hit you -- You're fortunate to have stainless steel armor!";
1555 p
= "\nThe %s hit you -- your armor feels weaker";
1560 i
= rnd(15) + 8 - c
[AC
];
1561 spout
: p
= "\nThe %s breathes fire at you!";
1562 if (c
[FIRERESISTANCE
])
1563 p
= "\nThe %s's flame doesn't faze you!";
1566 lprintf(p
, lastmonst
);
1573 i
= rnd(20) + 25 - c
[AC
];
1577 if (c
[STRENGTH
] > 3) {
1578 p
= "\nThe %s stung you! You feel weaker";
1582 p
= "\nThe %s stung you!";
1586 p
= "\nThe %s blasts you with his cold breath";
1587 i
= rnd(15) + 18 - c
[AC
];
1591 lprintf("\nThe %s drains you of your life energy!", lastmonst
);
1597 p
= "\nThe %s got you with a gusher!";
1598 i
= rnd(15) + 25 - c
[AC
];
1603 return (0); /* he has a device of no theft */
1605 p
= "\nThe %s hit you -- Your purse feels lighter";
1606 if (c
[GOLD
] > 32767)
1609 c
[GOLD
] -= rnd((int) (1 + (c
[GOLD
] >> 1)));
1613 p
= "\nThe %s couldn't find any gold to steal";
1614 lprintf(p
, lastmonst
);
1621 for (j
= 50;;) {/* disenchant */
1623 m
= iven
[i
]; /* randomly select item */
1624 if (m
> 0 && ivenarg
[i
] > 0 && m
!= OSCROLL
&& m
!= OPOTION
) {
1625 if ((ivenarg
[i
] -= 3) < 0)
1627 lprintf("\nThe %s hits you -- you feel a sense of loss", lastmonst
);
1635 p
= "\nThe %s nearly misses";
1643 p
= "\nThe %s hit you with his barbed tail";
1644 i
= rnd(25) - c
[AC
];
1648 p
= "\nThe %s has confused you";
1650 c
[CONFUSE
] += 10 + rnd(10);
1653 case 12: /* performs any number of other special
1655 return (spattack(spsel
[rund(10)], xx
, yy
));
1658 p
= "\nThe %s flattens you with his psionics!";
1659 i
= rnd(15) + 30 - c
[AC
];
1664 return (0); /* he has device of no theft */
1665 if (emptyhanded() == 1) {
1666 p
= "\nThe %s couldn't find anything to steal";
1669 lprintf("\nThe %s picks your pocket and takes:", lastmonst
);
1671 if (stealsomething() == 0)
1678 i
= rnd(10) + 5 - c
[AC
];
1679 spout3
: p
= "\nThe %s bit you!";
1683 i
= rnd(15) + 10 - c
[AC
];
1687 lprintf(p
, lastmonst
);
1694 * checkloss(x) Routine to subtract hp from user and flag bottomline display
1697 * Routine to subtract hitpoints from the user and flag the bottomline display
1698 * Enter with the number of hit points to lose
1699 * Note: if x > c[HP] this routine could kill the player!
1711 * annihilate() Routine to annihilate all monsters around player (playerx,playery)
1713 * Gives player experience, but no dropped objects
1714 * Returns the experience gained from all monsters killed
1722 for (k
= 0, i
= playerx
- 1; i
<= playerx
+ 1; i
++)
1723 for (j
= playery
- 1; j
<= playery
+ 1; j
++)
1724 if (!vxy(&i
, &j
)) { /* if not out of bounds */
1725 if (*(p
= &mitem
[i
][j
])) { /* if a monster there */
1726 if (*p
< DEMONLORD
+ 2) {
1727 k
+= monster
[*p
].experience
;
1728 *p
= know
[i
][j
] = 0;
1730 lprintf("\nThe %s barely escapes being annihilated!", monster
[*p
].name
);
1731 hitp
[i
][j
] = (hitp
[i
][j
] >> 1) + 1; /* lose half hit points */
1736 lprcat("\nYou hear loud screams of agony!");
1737 raiseexperience((long) k
);
1743 * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
1744 * int x,y,dir,lifetime;
1746 * Enter with the coordinates of the sphere in x,y
1747 * the direction (0-8 diroffx format) in dir, and the lifespan of the
1748 * sphere in lifetime (in turns)
1749 * Returns the number of spheres currently in existence
1752 newsphere(int x
, int y
, int dir
, int life
)
1756 if (((sp
= (struct sphere
*) malloc(sizeof(struct sphere
)))) == 0)
1757 return (c
[SPHCAST
]); /* can't malloc, therefore failure */
1759 dir
= 0; /* no movement if direction not found */
1761 vxy(&x
, &y
); /* don't go out of bounds */
1772 if ((m
= mitem
[x
][y
]) >= DEMONLORD
+ 4) { /* demons dispel spheres */
1774 show1cell(x
, y
);/* show the demon (ha ha) */
1776 lprintf("\nThe %s dispels the sphere!", monster
[m
].name
);
1778 rmsphere(x
, y
); /* remove any spheres that are here */
1780 return (c
[SPHCAST
]);
1782 if (m
== DISENCHANTRESS
) { /* disenchantress cancels spheres */
1784 lprintf("\nThe %s causes cancellation of the sphere!", monster
[m
].name
);
1786 boom
: sphboom(x
, y
); /* blow up stuff around sphere */
1787 rmsphere(x
, y
); /* remove any spheres that are here */
1789 return (c
[SPHCAST
]);
1791 if (c
[CANCELLATION
]) { /* cancellation cancels spheres */
1793 lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!");
1797 if (item
[x
][y
] == OANNIHILATION
) { /* collision of spheres
1798 * detonates spheres */
1800 lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!");
1805 if (playerx
== x
&& playery
== y
) { /* collision of sphere and
1808 lprcat("\nYou have been enveloped by the zone of nothingness!\n");
1810 rmsphere(x
, y
); /* remove any spheres that are here */
1814 item
[x
][y
] = OANNIHILATION
;
1817 show1cell(x
, y
); /* show the new sphere */
1822 sp
->lifetime
= life
;
1825 spheres
= sp
; /* if first node in the sphere list */
1826 else { /* add sphere to beginning of linked list */
1830 return (++c
[SPHCAST
]); /* one more sphere in the world */
1834 * rmsphere(x,y) Function to delete a sphere of annihilation from list
1837 * Enter with the coordinates of the sphere (on current level)
1838 * Returns the number of spheres currently in existence
1841 rmsphere(int x
, int y
)
1843 struct sphere
*sp
, *sp2
= 0;
1844 for (sp
= spheres
; sp
; sp2
= sp
, sp
= sp
->p
)
1845 if (level
== sp
->lev
) /* is sphere on this level? */
1846 if ((x
== sp
->x
) && (y
== sp
->y
)) { /* locate sphere at this
1848 item
[x
][y
] = mitem
[x
][y
] = 0;
1850 show1cell(x
, y
); /* show the now missing
1853 if (sp
== spheres
) {
1864 return (c
[SPHCAST
]); /* return number of spheres in the world */
1868 * sphboom(x,y) Function to perform the effects of a sphere detonation
1871 * Enter with the coordinates of the blast, Returns no value
1874 sphboom(int x
, int y
)
1879 if (c
[CANCELLATION
])
1880 c
[CANCELLATION
] = 1;
1881 for (j
= max(1, x
- 2); j
< min(x
+ 3, MAXX
- 1); j
++)
1882 for (i
= max(1, y
- 2); i
< min(y
+ 3, MAXY
- 1); i
++) {
1883 item
[j
][i
] = mitem
[j
][i
] = 0;
1885 if (playerx
== j
&& playery
== i
) {
1888 lprcat("\nYou were too close to the sphere!");
1890 died(283); /* player killed in explosion */
1896 * genmonst() Function to ask for monster and genocide from game
1898 * This is done by setting a flag in the monster[] structure
1905 lprcat("\nGenocide what monster? ");
1906 for (i
= 0; (!isalpha(i
)) && (i
!= ' '); i
= ttgetch());
1908 for (j
= 0; j
< MAXMONST
; j
++) /* search for the monster type */
1909 if (monstnamelist
[j
] == i
) { /* have we found it? */
1910 monster
[j
].genocided
= 1; /* genocided from game */
1911 lprintf(" There will be no more %s's", monster
[j
].name
);
1912 /* now wipe out monsters on this level */
1913 newcavelevel(level
);
1914 draws(0, MAXX
, 0, MAXY
);
1918 lprcat(" You sense failure!");