monster.c revision 1.14 1 1.14 dholland /* $NetBSD: monster.c,v 1.14 2008/02/03 19:20:42 dholland Exp $ */
2 1.2 mycroft
3 1.1 cgd /*
4 1.5 christos * monster.c Larn is copyrighted 1986 by Noah Morgan.
5 1.1 cgd *
6 1.5 christos * This file contains the following functions:
7 1.5 christos * ----------------------------------------------------------------------------
8 1.1 cgd *
9 1.5 christos * createmonster(monstno) Function to create a monster next to the player
10 1.5 christos * int monstno;
11 1.1 cgd *
12 1.5 christos * int cgood(x,y,itm,monst)Function to check location for emptiness
13 1.5 christos * int x,y,itm,monst;
14 1.1 cgd *
15 1.5 christos * createitem(it,arg) Routine to place an item next to the player
16 1.5 christos * int it,arg;
17 1.1 cgd *
18 1.5 christos * cast() Subroutine called by parse to cast a spell for the user
19 1.1 cgd *
20 1.5 christos * speldamage(x) Function to perform spell functions cast by the player
21 1.5 christos * int x;
22 1.1 cgd *
23 1.5 christos * loseint() Routine to decrement your int (intelligence) if > 3
24 1.1 cgd *
25 1.5 christos * isconfuse() Routine to check to see if player is confused
26 1.1 cgd *
27 1.5 christos * nospell(x,monst)Routine to return 1 if a spell doesn't affect a monster
28 1.5 christos * int x,monst;
29 1.1 cgd *
30 1.5 christos * fullhit(xx) Function to return full damage against a monst (aka web)
31 1.5 christos * int xx;
32 1.1 cgd *
33 1.5 christos * direct(spnum,dam,str,arg)Routine to direct spell damage 1 square in 1 dir
34 1.5 christos * int spnum,dam,arg;
35 1.5 christos * char *str;
36 1.1 cgd *
37 1.5 christos * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
38 1.5 christos * int spnum,dam,delay;
39 1.5 christos * char *str,cshow;
40 1.1 cgd *
41 1.5 christos * ifblind(x,y)Routine to put "monster" or the monster name into lastmosnt
42 1.5 christos * int x,y;
43 1.1 cgd *
44 1.5 christos * tdirect(spnum) Routine to teleport away a monster
45 1.5 christos * int spnum;
46 1.1 cgd *
47 1.5 christos * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
48 1.5 christos * int sp,dam;
49 1.5 christos * char *str;
50 1.1 cgd *
51 1.5 christos * dirsub(x,y) Routine to ask for direction, then modify x,y for it
52 1.5 christos * int *x,*y;
53 1.1 cgd *
54 1.5 christos * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds
55 1.5 christos * int *x,*y;
56 1.1 cgd *
57 1.5 christos * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
58 1.5 christos * int spnum;
59 1.1 cgd *
60 1.5 christos * hitmonster(x,y) Function to hit a monster at the designated coordinates
61 1.5 christos * int x,y;
62 1.1 cgd *
63 1.5 christos * hitm(x,y,amt) Function to just hit a monster at a given coordinates
64 1.5 christos * int x,y,amt;
65 1.1 cgd *
66 1.5 christos * hitplayer(x,y) Function for the monster to hit the player from (x,y)
67 1.5 christos * int x,y;
68 1.1 cgd *
69 1.5 christos * dropsomething(monst) Function to create an object when a monster dies
70 1.5 christos * int monst;
71 1.1 cgd *
72 1.5 christos * dropgold(amount) Function to drop some gold around player
73 1.5 christos * int amount;
74 1.1 cgd *
75 1.5 christos * something(level) Function to create a random item around player
76 1.5 christos * int level;
77 1.1 cgd *
78 1.5 christos * newobject(lev,i) Routine to return a randomly selected new object
79 1.5 christos * int lev,*i;
80 1.1 cgd *
81 1.5 christos * spattack(atckno,xx,yy) Function to process special attacks from monsters
82 1.5 christos * int atckno,xx,yy;
83 1.1 cgd *
84 1.5 christos * checkloss(x) Routine to subtract hp from user and flag bottomline display
85 1.5 christos * int x;
86 1.1 cgd *
87 1.5 christos * annihilate() Routine to annihilate monsters around player, playerx,playery
88 1.1 cgd *
89 1.5 christos * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
90 1.5 christos * int x,y,dir,lifetime;
91 1.1 cgd *
92 1.5 christos * rmsphere(x,y) Function to delete a sphere of annihilation from list
93 1.5 christos * int x,y;
94 1.1 cgd *
95 1.5 christos * sphboom(x,y) Function to perform the effects of a sphere detonation
96 1.5 christos * int x,y;
97 1.1 cgd *
98 1.5 christos * genmonst() Function to ask for monster and genocide from game
99 1.1 cgd *
100 1.1 cgd */
101 1.5 christos #include <sys/cdefs.h>
102 1.5 christos #ifndef lint
103 1.14 dholland __RCSID("$NetBSD: monster.c,v 1.14 2008/02/03 19:20:42 dholland Exp $");
104 1.5 christos #endif /* not lint */
105 1.5 christos
106 1.5 christos #include <string.h>
107 1.5 christos #include <stdlib.h>
108 1.1 cgd #include "header.h"
109 1.5 christos #include "extern.h"
110 1.1 cgd
111 1.5 christos struct isave { /* used for altar reality */
112 1.5 christos char type; /* 0=item, 1=monster */
113 1.5 christos char id; /* item number or monster number */
114 1.5 christos short arg; /* the type of item or hitpoints of monster */
115 1.5 christos };
116 1.1 cgd
117 1.14 dholland static int cgood(int, int, int, int);
118 1.8 jsm static int dirsub(int *, int *);
119 1.14 dholland static void dropsomething(int);
120 1.14 dholland static int spattack(int, int, int);
121 1.14 dholland
122 1.1 cgd /*
123 1.5 christos * createmonster(monstno) Function to create a monster next to the player
124 1.5 christos * int monstno;
125 1.1 cgd *
126 1.5 christos * Enter with the monster number (1 to MAXMONST+8)
127 1.5 christos * Returns no value.
128 1.1 cgd */
129 1.5 christos void
130 1.1 cgd createmonster(mon)
131 1.5 christos int mon;
132 1.5 christos {
133 1.5 christos int x, y, k, i;
134 1.5 christos if (mon < 1 || mon > MAXMONST + 8) { /* check for monster number
135 1.5 christos * out of bounds */
136 1.5 christos beep();
137 1.12 dholland lprintf("\ncan't createmonst(%ld)\n", (long) mon);
138 1.5 christos nap(3000);
139 1.5 christos return;
140 1.5 christos }
141 1.5 christos while (monster[mon].genocided && mon < MAXMONST)
142 1.5 christos mon++; /* genocided? */
143 1.5 christos for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction,
144 1.5 christos * then try all */
145 1.5 christos if (k > 8)
146 1.5 christos k = 1; /* wraparound the diroff arrays */
147 1.5 christos x = playerx + diroffx[k];
148 1.5 christos y = playery + diroffy[k];
149 1.5 christos if (cgood(x, y, 0, 1)) { /* if we can create here */
150 1.1 cgd mitem[x][y] = mon;
151 1.1 cgd hitp[x][y] = monster[mon].hitpoints;
152 1.5 christos stealth[x][y] = know[x][y] = 0;
153 1.5 christos switch (mon) {
154 1.5 christos case ROTHE:
155 1.5 christos case POLTERGEIST:
156 1.5 christos case VAMPIRE:
157 1.5 christos stealth[x][y] = 1;
158 1.5 christos };
159 1.1 cgd return;
160 1.1 cgd }
161 1.1 cgd }
162 1.5 christos }
163 1.1 cgd
164 1.1 cgd /*
165 1.5 christos * int cgood(x,y,itm,monst) Function to check location for emptiness
166 1.5 christos * int x,y,itm,monst;
167 1.1 cgd *
168 1.5 christos * Routine to return TRUE if a location does not have itm or monst there
169 1.5 christos * returns FALSE (0) otherwise
170 1.5 christos * Enter with itm or monst TRUE or FALSE if checking it
171 1.5 christos * Example: if itm==TRUE check for no item at this location
172 1.5 christos * if monst==TRUE check for no monster at this location
173 1.5 christos * This routine will return FALSE if at a wall or the dungeon exit on level 1
174 1.5 christos */
175 1.14 dholland static int
176 1.13 dholland cgood(int x, int y, int theitem, int monst)
177 1.5 christos {
178 1.13 dholland #define itm __lose
179 1.5 christos if ((y >= 0) && (y <= MAXY - 1) && (x >= 0) && (x <= MAXX - 1))
180 1.5 christos /* within bounds? */
181 1.5 christos if (item[x][y] != OWALL) /* can't make anything on walls */
182 1.5 christos /* is it free of items? */
183 1.13 dholland if (theitem == 0 || (item[x][y] == 0))
184 1.5 christos /* is it free of monsters? */
185 1.5 christos if (monst == 0 || (mitem[x][y] == 0))
186 1.5 christos if ((level != 1) || (x != 33) ||
187 1.5 christos (y != MAXY - 1))
188 1.5 christos /* not exit to level 1 */
189 1.5 christos return (1);
190 1.5 christos return (0);
191 1.5 christos }
192 1.5 christos
193 1.5 christos /*
194 1.5 christos * createitem(it,arg) Routine to place an item next to the player
195 1.5 christos * int it,arg;
196 1.5 christos *
197 1.5 christos * Enter with the item number and its argument (iven[], ivenarg[])
198 1.5 christos * Returns no value, thus we don't know about createitem() failures.
199 1.5 christos */
200 1.5 christos void
201 1.5 christos createitem(it, arg)
202 1.5 christos int it, arg;
203 1.5 christos {
204 1.5 christos int x, y, k, i;
205 1.5 christos if (it >= MAXOBJ)
206 1.5 christos return; /* no such object */
207 1.5 christos for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction,
208 1.5 christos * then try all */
209 1.5 christos if (k > 8)
210 1.5 christos k = 1; /* wraparound the diroff arrays */
211 1.5 christos x = playerx + diroffx[k];
212 1.5 christos y = playery + diroffy[k];
213 1.5 christos if (cgood(x, y, 1, 0)) { /* if we can create here */
214 1.5 christos item[x][y] = it;
215 1.5 christos know[x][y] = 0;
216 1.5 christos iarg[x][y] = arg;
217 1.5 christos return;
218 1.1 cgd }
219 1.1 cgd }
220 1.5 christos }
221 1.1 cgd
222 1.1 cgd /*
223 1.5 christos * cast() Subroutine called by parse to cast a spell for the user
224 1.1 cgd *
225 1.5 christos * No arguments and no return value.
226 1.1 cgd */
227 1.5 christos static char eys[] = "\nEnter your spell: ";
228 1.5 christos void
229 1.1 cgd cast()
230 1.5 christos {
231 1.5 christos int i, j, a, b, d;
232 1.1 cgd cursors();
233 1.5 christos if (c[SPELLS] <= 0) {
234 1.5 christos lprcat("\nYou don't have any spells!");
235 1.5 christos return;
236 1.5 christos }
237 1.5 christos lprcat(eys);
238 1.5 christos --c[SPELLS];
239 1.7 christos while ((a = lgetchar()) == 'D') {
240 1.5 christos seemagic(-1);
241 1.5 christos cursors();
242 1.5 christos lprcat(eys);
243 1.5 christos }
244 1.5 christos if (a == '\33')
245 1.5 christos goto over; /* to escape casting a spell */
246 1.7 christos if ((b = lgetchar()) == '\33')
247 1.5 christos goto over; /* to escape casting a spell */
248 1.7 christos if ((d = lgetchar()) == '\33') {
249 1.5 christos over: lprcat(aborted);
250 1.5 christos c[SPELLS]++;
251 1.5 christos return;
252 1.5 christos } /* to escape casting a spell */
253 1.1 cgd #ifdef EXTRA
254 1.1 cgd c[SPELLSCAST]++;
255 1.1 cgd #endif
256 1.5 christos for (lprc('\n'), j = -1, i = 0; i < SPNUM; i++) /* seq search for his
257 1.5 christos * spell, hash? */
258 1.5 christos if ((spelcode[i][0] == a) && (spelcode[i][1] == b) && (spelcode[i][2] == d))
259 1.5 christos if (spelknow[i]) {
260 1.5 christos speldamage(i);
261 1.5 christos j = 1;
262 1.5 christos i = SPNUM;
263 1.5 christos }
264 1.5 christos if (j == -1)
265 1.5 christos lprcat(" Nothing Happened ");
266 1.1 cgd bottomline();
267 1.5 christos }
268 1.1 cgd
269 1.1 cgd /*
270 1.5 christos * speldamage(x) Function to perform spell functions cast by the player
271 1.5 christos * int x;
272 1.1 cgd *
273 1.5 christos * Enter with the spell number, returns no value.
274 1.5 christos * Please insure that there are 2 spaces before all messages here
275 1.1 cgd */
276 1.5 christos void
277 1.13 dholland speldamage(int x)
278 1.5 christos {
279 1.5 christos int i, j, clev;
280 1.5 christos int xl, xh, yl, yh;
281 1.13 dholland u_char *p, *kn, *pm;
282 1.13 dholland
283 1.5 christos if (x >= SPNUM)
284 1.5 christos return; /* no such spell */
285 1.5 christos if (c[TIMESTOP]) {
286 1.5 christos lprcat(" It didn't seem to work");
287 1.5 christos return;
288 1.5 christos } /* not if time stopped */
289 1.1 cgd clev = c[LEVEL];
290 1.5 christos if ((rnd(23) == 7) || (rnd(18) > c[INTELLIGENCE])) {
291 1.5 christos lprcat(" It didn't work!");
292 1.5 christos return;
293 1.5 christos }
294 1.5 christos if (clev * 3 + 2 < x) {
295 1.5 christos lprcat(" Nothing happens. You seem inexperienced at this");
296 1.5 christos return;
297 1.5 christos }
298 1.5 christos switch (x) {
299 1.5 christos /* ----- LEVEL 1 SPELLS ----- */
300 1.5 christos
301 1.5 christos case 0:
302 1.5 christos if (c[PROTECTIONTIME] == 0)
303 1.5 christos c[MOREDEFENSES] += 2; /* protection field +2 */
304 1.5 christos c[PROTECTIONTIME] += 250;
305 1.5 christos return;
306 1.5 christos
307 1.5 christos case 1:
308 1.5 christos i = rnd(((clev + 1) << 1)) + clev + 3;
309 1.5 christos godirect(x, i, (clev >= 2) ? " Your missiles hit the %s" : " Your missile hit the %s", 100, '+'); /* magic missile */
310 1.5 christos
311 1.5 christos return;
312 1.5 christos
313 1.5 christos case 2:
314 1.5 christos if (c[DEXCOUNT] == 0)
315 1.5 christos c[DEXTERITY] += 3; /* dexterity */
316 1.5 christos c[DEXCOUNT] += 400;
317 1.5 christos return;
318 1.5 christos
319 1.13 dholland case 3: /* sleep */
320 1.5 christos i = rnd(3) + 1;
321 1.13 dholland direct(x, fullhit(i),
322 1.13 dholland " While the %s slept, you smashed it %ld times", i);
323 1.5 christos return;
324 1.1 cgd
325 1.5 christos case 4: /* charm monster */
326 1.5 christos c[CHARMCOUNT] += c[CHARISMA] << 1;
327 1.5 christos return;
328 1.5 christos
329 1.5 christos case 5:
330 1.5 christos godirect(x, rnd(10) + 15 + clev, " The sound damages the %s", 70, '@'); /* sonic spear */
331 1.5 christos return;
332 1.5 christos
333 1.5 christos /* ----- LEVEL 2 SPELLS ----- */
334 1.1 cgd
335 1.13 dholland case 6: /* web */
336 1.5 christos i = rnd(3) + 2;
337 1.13 dholland direct(x, fullhit(i),
338 1.13 dholland " While the %s is entangled, you hit %ld times", i);
339 1.13 dholland return;
340 1.5 christos
341 1.5 christos case 7:
342 1.5 christos if (c[STRCOUNT] == 0)
343 1.5 christos c[STREXTRA] += 3; /* strength */
344 1.5 christos c[STRCOUNT] += 150 + rnd(100);
345 1.5 christos return;
346 1.1 cgd
347 1.5 christos case 8:
348 1.5 christos yl = playery - 5; /* enlightenment */
349 1.5 christos yh = playery + 6;
350 1.5 christos xl = playerx - 15;
351 1.5 christos xh = playerx + 16;
352 1.5 christos vxy(&xl, &yl);
353 1.5 christos vxy(&xh, &yh); /* check bounds */
354 1.5 christos for (i = yl; i <= yh; i++) /* enlightenment */
355 1.5 christos for (j = xl; j <= xh; j++)
356 1.5 christos know[j][i] = 1;
357 1.5 christos draws(xl, xh + 1, yl, yh + 1);
358 1.5 christos return;
359 1.1 cgd
360 1.5 christos case 9:
361 1.5 christos raisehp(20 + (clev << 1));
362 1.5 christos return; /* healing */
363 1.5 christos
364 1.5 christos case 10:
365 1.5 christos c[BLINDCOUNT] = 0;
366 1.5 christos return; /* cure blindness */
367 1.1 cgd
368 1.5 christos case 11:
369 1.5 christos createmonster(makemonst(level + 1) + 8);
370 1.5 christos return;
371 1.1 cgd
372 1.5 christos case 12:
373 1.5 christos if (rnd(11) + 7 <= c[WISDOM])
374 1.5 christos direct(x, rnd(20) + 20 + clev, " The %s believed!", 0);
375 1.5 christos else
376 1.5 christos lprcat(" It didn't believe the illusions!");
377 1.5 christos return;
378 1.1 cgd
379 1.5 christos case 13: /* if he has the amulet of invisibility then
380 1.5 christos * add more time */
381 1.5 christos for (j = i = 0; i < 26; i++)
382 1.5 christos if (iven[i] == OAMULET)
383 1.5 christos j += 1 + ivenarg[i];
384 1.5 christos c[INVISIBILITY] += (j << 7) + 12;
385 1.5 christos return;
386 1.1 cgd
387 1.5 christos /* ----- LEVEL 3 SPELLS ----- */
388 1.1 cgd
389 1.5 christos case 14:
390 1.5 christos godirect(x, rnd(25 + clev) + 25 + clev, " The fireball hits the %s", 40, '*');
391 1.5 christos return; /* fireball */
392 1.1 cgd
393 1.5 christos case 15:
394 1.5 christos godirect(x, rnd(25) + 20 + clev, " Your cone of cold strikes the %s", 60, 'O'); /* cold */
395 1.5 christos return;
396 1.1 cgd
397 1.5 christos case 16:
398 1.5 christos dirpoly(x);
399 1.5 christos return; /* polymorph */
400 1.5 christos
401 1.5 christos case 17:
402 1.5 christos c[CANCELLATION] += 5 + clev;
403 1.5 christos return; /* cancellation */
404 1.5 christos
405 1.5 christos case 18:
406 1.5 christos c[HASTESELF] += 7 + clev;
407 1.5 christos return; /* haste self */
408 1.1 cgd
409 1.5 christos case 19:
410 1.5 christos omnidirect(x, 30 + rnd(10), " The %s gasps for air"); /* cloud kill */
411 1.5 christos return;
412 1.1 cgd
413 1.5 christos case 20:
414 1.5 christos xh = min(playerx + 1, MAXX - 2);
415 1.5 christos yh = min(playery + 1, MAXY - 2);
416 1.5 christos for (i = max(playerx - 1, 1); i <= xh; i++) /* vaporize rock */
417 1.5 christos for (j = max(playery - 1, 1); j <= yh; j++) {
418 1.5 christos kn = &know[i][j];
419 1.5 christos pm = &mitem[i][j];
420 1.5 christos switch (*(p = &item[i][j])) {
421 1.5 christos case OWALL:
422 1.5 christos if (level < MAXLEVEL + MAXVLEVEL - 1)
423 1.5 christos *p = *kn = 0;
424 1.5 christos break;
425 1.1 cgd
426 1.5 christos case OSTATUE:
427 1.5 christos if (c[HARDGAME] < 3) {
428 1.5 christos *p = OBOOK;
429 1.5 christos iarg[i][j] = level;
430 1.5 christos *kn = 0;
431 1.5 christos }
432 1.5 christos break;
433 1.1 cgd
434 1.5 christos case OTHRONE:
435 1.5 christos *pm = GNOMEKING;
436 1.5 christos *kn = 0;
437 1.5 christos *p = OTHRONE2;
438 1.5 christos hitp[i][j] = monster[GNOMEKING].hitpoints;
439 1.5 christos break;
440 1.1 cgd
441 1.5 christos case OALTAR:
442 1.5 christos *pm = DEMONPRINCE;
443 1.5 christos *kn = 0;
444 1.5 christos hitp[i][j] = monster[DEMONPRINCE].hitpoints;
445 1.5 christos break;
446 1.5 christos };
447 1.5 christos switch (*pm) {
448 1.5 christos case XORN:
449 1.5 christos ifblind(i, j);
450 1.5 christos hitm(i, j, 200);
451 1.5 christos break; /* Xorn takes damage from vpr */
452 1.5 christos }
453 1.5 christos }
454 1.5 christos return;
455 1.1 cgd
456 1.5 christos /* ----- LEVEL 4 SPELLS ----- */
457 1.1 cgd
458 1.5 christos case 21:
459 1.5 christos direct(x, 100 + clev, " The %s shrivels up", 0); /* dehydration */
460 1.5 christos return;
461 1.1 cgd
462 1.5 christos case 22:
463 1.5 christos godirect(x, rnd(25) + 20 + (clev << 1), " A lightning bolt hits the %s", 1, '~'); /* lightning */
464 1.5 christos return;
465 1.1 cgd
466 1.5 christos case 23:
467 1.5 christos i = min(c[HP] - 1, c[HPMAX] / 2); /* drain life */
468 1.5 christos direct(x, i + i, "", 0);
469 1.5 christos c[HP] -= i;
470 1.5 christos return;
471 1.1 cgd
472 1.5 christos case 24:
473 1.5 christos if (c[GLOBE] == 0)
474 1.5 christos c[MOREDEFENSES] += 10;
475 1.5 christos c[GLOBE] += 200;
476 1.5 christos loseint(); /* globe of invulnerability */
477 1.5 christos return;
478 1.1 cgd
479 1.5 christos case 25:
480 1.5 christos omnidirect(x, 32 + clev, " The %s struggles for air in your flood!"); /* flood */
481 1.5 christos return;
482 1.1 cgd
483 1.5 christos case 26:
484 1.5 christos if (rnd(151) == 63) {
485 1.5 christos beep();
486 1.5 christos lprcat("\nYour heart stopped!\n");
487 1.5 christos nap(4000);
488 1.5 christos died(270);
489 1.5 christos return;
490 1.5 christos }
491 1.5 christos if (c[WISDOM] > rnd(10) + 10)
492 1.5 christos direct(x, 2000, " The %s's heart stopped", 0); /* finger of death */
493 1.5 christos else
494 1.5 christos lprcat(" It didn't work");
495 1.5 christos return;
496 1.1 cgd
497 1.5 christos /* ----- LEVEL 5 SPELLS ----- */
498 1.1 cgd
499 1.5 christos case 27:
500 1.5 christos c[SCAREMONST] += rnd(10) + clev;
501 1.5 christos return; /* scare monster */
502 1.5 christos
503 1.5 christos case 28:
504 1.5 christos c[HOLDMONST] += rnd(10) + clev;
505 1.5 christos return; /* hold monster */
506 1.5 christos
507 1.5 christos case 29:
508 1.5 christos c[TIMESTOP] += rnd(20) + (clev << 1);
509 1.5 christos return; /* time stop */
510 1.5 christos
511 1.5 christos case 30:
512 1.5 christos tdirect(x);
513 1.5 christos return; /* teleport away */
514 1.1 cgd
515 1.5 christos case 31:
516 1.5 christos omnidirect(x, 35 + rnd(10) + clev, " The %s cringes from the flame"); /* magic fire */
517 1.5 christos return;
518 1.1 cgd
519 1.5 christos /* ----- LEVEL 6 SPELLS ----- */
520 1.5 christos
521 1.5 christos case 32:
522 1.5 christos if ((rnd(23) == 5) && (wizard == 0)) { /* sphere of
523 1.5 christos * annihilation */
524 1.5 christos beep();
525 1.5 christos lprcat("\nYou have been enveloped by the zone of nothingness!\n");
526 1.5 christos nap(4000);
527 1.5 christos died(258);
528 1.5 christos return;
529 1.5 christos }
530 1.5 christos xl = playerx;
531 1.5 christos yl = playery;
532 1.5 christos loseint();
533 1.5 christos i = dirsub(&xl, &yl); /* get direction of sphere */
534 1.5 christos newsphere(xl, yl, i, rnd(20) + 11); /* make a sphere */
535 1.5 christos return;
536 1.5 christos
537 1.5 christos case 33:
538 1.5 christos genmonst();
539 1.5 christos spelknow[33] = 0; /* genocide */
540 1.5 christos loseint();
541 1.5 christos return;
542 1.5 christos
543 1.5 christos case 34: /* summon demon */
544 1.5 christos if (rnd(100) > 30) {
545 1.5 christos direct(x, 150, " The demon strikes at the %s", 0);
546 1.5 christos return;
547 1.5 christos }
548 1.5 christos if (rnd(100) > 15) {
549 1.5 christos lprcat(" Nothing seems to have happened");
550 1.5 christos return;
551 1.5 christos }
552 1.5 christos lprcat(" The demon turned on you and vanished!");
553 1.5 christos beep();
554 1.5 christos i = rnd(40) + 30;
555 1.5 christos lastnum = 277;
556 1.5 christos losehp(i); /* must say killed by a demon */
557 1.5 christos return;
558 1.5 christos
559 1.5 christos case 35: /* walk through walls */
560 1.5 christos c[WTW] += rnd(10) + 5;
561 1.5 christos return;
562 1.5 christos
563 1.5 christos case 36: /* alter reality */
564 1.5 christos {
565 1.5 christos struct isave *save; /* pointer to item save
566 1.5 christos * structure */
567 1.5 christos int sc;
568 1.5 christos sc = 0; /* # items saved */
569 1.5 christos save = (struct isave *) malloc(sizeof(struct isave) * MAXX * MAXY * 2);
570 1.5 christos for (j = 0; j < MAXY; j++)
571 1.5 christos for (i = 0; i < MAXX; i++) { /* save all items and
572 1.5 christos * monsters */
573 1.5 christos xl = item[i][j];
574 1.5 christos if (xl && xl != OWALL && xl != OANNIHILATION) {
575 1.5 christos save[sc].type = 0;
576 1.5 christos save[sc].id = item[i][j];
577 1.5 christos save[sc++].arg = iarg[i][j];
578 1.5 christos }
579 1.5 christos if (mitem[i][j]) {
580 1.5 christos save[sc].type = 1;
581 1.5 christos save[sc].id = mitem[i][j];
582 1.5 christos save[sc++].arg = hitp[i][j];
583 1.5 christos }
584 1.5 christos item[i][j] = OWALL;
585 1.5 christos mitem[i][j] = 0;
586 1.5 christos if (wizard)
587 1.5 christos know[i][j] = 1;
588 1.5 christos else
589 1.5 christos know[i][j] = 0;
590 1.5 christos }
591 1.5 christos eat(1, 1);
592 1.5 christos if (level == 1)
593 1.5 christos item[33][MAXY - 1] = 0;
594 1.5 christos for (j = rnd(MAXY - 2), i = 1; i < MAXX - 1; i++)
595 1.5 christos item[i][j] = 0;
596 1.5 christos while (sc > 0) { /* put objects back in level */
597 1.5 christos --sc;
598 1.5 christos if (save[sc].type == 0) {
599 1.5 christos int trys;
600 1.5 christos for (trys = 100, i = j = 1; --trys > 0 && item[i][j]; i = rnd(MAXX - 1), j = rnd(MAXY - 1));
601 1.5 christos if (trys) {
602 1.5 christos item[i][j] = save[sc].id;
603 1.5 christos iarg[i][j] = save[sc].arg;
604 1.5 christos }
605 1.5 christos } else { /* put monsters back in */
606 1.5 christos int trys;
607 1.5 christos for (trys = 100, i = j = 1; --trys > 0 && (item[i][j] == OWALL || mitem[i][j]); i = rnd(MAXX - 1), j = rnd(MAXY - 1));
608 1.5 christos if (trys) {
609 1.5 christos mitem[i][j] = save[sc].id;
610 1.5 christos hitp[i][j] = save[sc].arg;
611 1.1 cgd }
612 1.5 christos }
613 1.5 christos }
614 1.5 christos loseint();
615 1.5 christos draws(0, MAXX, 0, MAXY);
616 1.5 christos if (wizard == 0)
617 1.5 christos spelknow[36] = 0;
618 1.5 christos free((char *) save);
619 1.5 christos positionplayer();
620 1.5 christos return;
621 1.5 christos }
622 1.1 cgd
623 1.5 christos case 37: /* permanence */
624 1.5 christos adjusttime(-99999L);
625 1.5 christos spelknow[37] = 0; /* forget */
626 1.5 christos loseint();
627 1.5 christos return;
628 1.1 cgd
629 1.5 christos default:
630 1.12 dholland lprintf(" spell %ld not available!", (long) x);
631 1.5 christos beep();
632 1.5 christos return;
633 1.5 christos };
634 1.5 christos }
635 1.1 cgd
636 1.1 cgd /*
637 1.5 christos * loseint() Routine to subtract 1 from your int (intelligence) if > 3
638 1.1 cgd *
639 1.5 christos * No arguments and no return value
640 1.1 cgd */
641 1.5 christos void
642 1.1 cgd loseint()
643 1.5 christos {
644 1.5 christos if (--c[INTELLIGENCE] < 3)
645 1.5 christos c[INTELLIGENCE] = 3;
646 1.5 christos }
647 1.1 cgd
648 1.1 cgd /*
649 1.5 christos * isconfuse() Routine to check to see if player is confused
650 1.1 cgd *
651 1.5 christos * This routine prints out a message saying "You can't aim your magic!"
652 1.5 christos * returns 0 if not confused, non-zero (time remaining confused) if confused
653 1.1 cgd */
654 1.5 christos int
655 1.1 cgd isconfuse()
656 1.5 christos {
657 1.5 christos if (c[CONFUSE]) {
658 1.5 christos lprcat(" You can't aim your magic!");
659 1.5 christos beep();
660 1.5 christos }
661 1.5 christos return (c[CONFUSE]);
662 1.5 christos }
663 1.5 christos
664 1.5 christos /*
665 1.5 christos * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
666 1.5 christos * int x,monst;
667 1.5 christos *
668 1.5 christos * Subroutine to return 1 if the spell can't affect the monster
669 1.5 christos * otherwise returns 0
670 1.5 christos * Enter with the spell number in x, and the monster number in monst.
671 1.5 christos */
672 1.5 christos int
673 1.5 christos nospell(x, monst)
674 1.5 christos int x, monst;
675 1.5 christos {
676 1.5 christos int tmp;
677 1.5 christos if (x >= SPNUM || monst >= MAXMONST + 8 || monst < 0 || x < 0)
678 1.5 christos return (0); /* bad spell or monst */
679 1.5 christos if ((tmp = spelweird[monst - 1][x]) == 0)
680 1.5 christos return (0);
681 1.5 christos cursors();
682 1.5 christos lprc('\n');
683 1.5 christos lprintf(spelmes[tmp], monster[monst].name);
684 1.5 christos return (1);
685 1.5 christos }
686 1.1 cgd
687 1.1 cgd /*
688 1.5 christos * fullhit(xx) Function to return full damage against a monster (aka web)
689 1.5 christos * int xx;
690 1.1 cgd *
691 1.5 christos * Function to return hp damage to monster due to a number of full hits
692 1.5 christos * Enter with the number of full hits being done
693 1.1 cgd */
694 1.5 christos int
695 1.1 cgd fullhit(xx)
696 1.5 christos int xx;
697 1.5 christos {
698 1.5 christos int i;
699 1.5 christos if (xx < 0 || xx > 20)
700 1.5 christos return (0); /* fullhits are out of range */
701 1.5 christos if (c[LANCEDEATH])
702 1.5 christos return (10000); /* lance of death */
703 1.5 christos i = xx * ((c[WCLASS] >> 1) + c[STRENGTH] + c[STREXTRA] - c[HARDGAME] - 12 + c[MOREDAM]);
704 1.5 christos return ((i >= 1) ? i : xx);
705 1.5 christos }
706 1.5 christos
707 1.5 christos /*
708 1.5 christos * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
709 1.5 christos * int spnum,dam,arg;
710 1.5 christos * char *str;
711 1.5 christos *
712 1.5 christos * Routine to ask for a direction to a spell and then hit the monster
713 1.5 christos * Enter with the spell number in spnum, the damage to be done in dam,
714 1.5 christos * lprintf format string in str, and lprintf's argument in arg.
715 1.5 christos * Returns no value.
716 1.5 christos */
717 1.5 christos void
718 1.5 christos direct(spnum, dam, str, arg)
719 1.5 christos int spnum, dam, arg;
720 1.13 dholland const char *str;
721 1.5 christos {
722 1.5 christos int x, y;
723 1.5 christos int m;
724 1.5 christos if (spnum < 0 || spnum >= SPNUM || str == 0)
725 1.5 christos return; /* bad arguments */
726 1.5 christos if (isconfuse())
727 1.5 christos return;
728 1.5 christos dirsub(&x, &y);
729 1.1 cgd m = mitem[x][y];
730 1.5 christos if (item[x][y] == OMIRROR) {
731 1.5 christos if (spnum == 3) { /* sleep */
732 1.5 christos lprcat("You fall asleep! ");
733 1.5 christos beep();
734 1.5 christos fool:
735 1.1 cgd arg += 2;
736 1.5 christos while (arg-- > 0) {
737 1.5 christos parse2();
738 1.5 christos nap(1000);
739 1.5 christos }
740 1.1 cgd return;
741 1.5 christos } else if (spnum == 6) { /* web */
742 1.5 christos lprcat("You get stuck in your own web! ");
743 1.5 christos beep();
744 1.1 cgd goto fool;
745 1.5 christos } else {
746 1.5 christos lastnum = 278;
747 1.11 mouse lprintf(str, "spell caster (that's you)", (long) arg);
748 1.5 christos beep();
749 1.5 christos losehp(dam);
750 1.5 christos return;
751 1.1 cgd }
752 1.1 cgd }
753 1.5 christos if (m == 0) {
754 1.5 christos lprcat(" There wasn't anything there!");
755 1.5 christos return;
756 1.5 christos }
757 1.5 christos ifblind(x, y);
758 1.5 christos if (nospell(spnum, m)) {
759 1.5 christos lasthx = x;
760 1.5 christos lasthy = y;
761 1.5 christos return;
762 1.5 christos }
763 1.5 christos lprintf(str, lastmonst, (long) arg);
764 1.5 christos hitm(x, y, dam);
765 1.5 christos }
766 1.5 christos
767 1.5 christos /*
768 1.5 christos * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
769 1.5 christos * int spnum,dam,delay;
770 1.5 christos * char *str,cshow;
771 1.5 christos *
772 1.5 christos * Function to hit in a direction from a missile weapon and have it keep
773 1.5 christos * on going in that direction until its power is exhausted
774 1.5 christos * Enter with the spell number in spnum, the power of the weapon in hp,
775 1.5 christos * lprintf format string in str, the # of milliseconds to delay between
776 1.5 christos * locations in delay, and the character to represent the weapon in cshow.
777 1.5 christos * Returns no value.
778 1.5 christos */
779 1.5 christos void
780 1.5 christos godirect(spnum, dam, str, delay, cshow)
781 1.5 christos int spnum, dam, delay;
782 1.13 dholland const char *str, cshow;
783 1.5 christos {
784 1.13 dholland u_char *p;
785 1.5 christos int x, y, m;
786 1.5 christos int dx, dy;
787 1.5 christos if (spnum < 0 || spnum >= SPNUM || str == 0 || delay < 0)
788 1.5 christos return; /* bad args */
789 1.5 christos if (isconfuse())
790 1.5 christos return;
791 1.5 christos dirsub(&dx, &dy);
792 1.5 christos x = dx;
793 1.5 christos y = dy;
794 1.5 christos dx = x - playerx;
795 1.5 christos dy = y - playery;
796 1.5 christos x = playerx;
797 1.5 christos y = playery;
798 1.5 christos while (dam > 0) {
799 1.5 christos x += dx;
800 1.5 christos y += dy;
801 1.5 christos if ((x > MAXX - 1) || (y > MAXY - 1) || (x < 0) || (y < 0)) {
802 1.5 christos dam = 0;
803 1.5 christos break; /* out of bounds */
804 1.5 christos }
805 1.5 christos if ((x == playerx) && (y == playery)) { /* if energy hits player */
806 1.5 christos cursors();
807 1.11 mouse lprcat("\nYou are hit by your own magic!");
808 1.5 christos beep();
809 1.5 christos lastnum = 278;
810 1.5 christos losehp(dam);
811 1.5 christos return;
812 1.5 christos }
813 1.5 christos if (c[BLINDCOUNT] == 0) { /* if not blind show effect */
814 1.5 christos cursor(x + 1, y + 1);
815 1.5 christos lprc(cshow);
816 1.5 christos nap(delay);
817 1.5 christos show1cell(x, y);
818 1.5 christos }
819 1.5 christos if ((m = mitem[x][y])) { /* is there a monster there? */
820 1.5 christos ifblind(x, y);
821 1.5 christos if (nospell(spnum, m)) {
822 1.5 christos lasthx = x;
823 1.5 christos lasthy = y;
824 1.5 christos return;
825 1.1 cgd }
826 1.5 christos cursors();
827 1.5 christos lprc('\n');
828 1.5 christos lprintf(str, lastmonst);
829 1.5 christos dam -= hitm(x, y, dam);
830 1.5 christos show1cell(x, y);
831 1.5 christos nap(1000);
832 1.5 christos x -= dx;
833 1.5 christos y -= dy;
834 1.5 christos } else
835 1.5 christos switch (*(p = &item[x][y])) {
836 1.5 christos case OWALL:
837 1.5 christos cursors();
838 1.5 christos lprc('\n');
839 1.5 christos lprintf(str, "wall");
840 1.5 christos if (dam >= 50 + c[HARDGAME]) /* enough damage? */
841 1.5 christos if (level < MAXLEVEL + MAXVLEVEL - 1) /* not on V3 */
842 1.5 christos if ((x < MAXX - 1) && (y < MAXY - 1) && (x) && (y)) {
843 1.1 cgd lprcat(" The wall crumbles");
844 1.5 christos god3: *p = 0;
845 1.5 christos god: know[x][y] = 0;
846 1.5 christos show1cell(x, y);
847 1.5 christos }
848 1.5 christos god2: dam = 0;
849 1.5 christos break;
850 1.5 christos
851 1.5 christos case OCLOSEDDOOR:
852 1.5 christos cursors();
853 1.5 christos lprc('\n');
854 1.5 christos lprintf(str, "door");
855 1.5 christos if (dam >= 40) {
856 1.5 christos lprcat(" The door is blasted apart");
857 1.5 christos goto god3;
858 1.5 christos }
859 1.5 christos goto god2;
860 1.5 christos
861 1.5 christos case OSTATUE:
862 1.5 christos cursors();
863 1.5 christos lprc('\n');
864 1.5 christos lprintf(str, "statue");
865 1.5 christos if (c[HARDGAME] < 3)
866 1.5 christos if (dam > 44) {
867 1.5 christos lprcat(" The statue crumbles");
868 1.5 christos *p = OBOOK;
869 1.5 christos iarg[x][y] = level;
870 1.1 cgd goto god;
871 1.5 christos }
872 1.5 christos goto god2;
873 1.1 cgd
874 1.5 christos case OTHRONE:
875 1.5 christos cursors();
876 1.5 christos lprc('\n');
877 1.5 christos lprintf(str, "throne");
878 1.5 christos if (dam > 39) {
879 1.5 christos mitem[x][y] = GNOMEKING;
880 1.5 christos hitp[x][y] = monster[GNOMEKING].hitpoints;
881 1.5 christos *p = OTHRONE2;
882 1.5 christos goto god;
883 1.5 christos }
884 1.5 christos goto god2;
885 1.5 christos
886 1.5 christos case OMIRROR:
887 1.5 christos dx *= -1;
888 1.5 christos dy *= -1;
889 1.5 christos break;
890 1.1 cgd };
891 1.5 christos dam -= 3 + (c[HARDGAME] >> 1);
892 1.1 cgd }
893 1.5 christos }
894 1.1 cgd
895 1.1 cgd /*
896 1.5 christos * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
897 1.5 christos * int x,y;
898 1.1 cgd *
899 1.5 christos * Subroutine to copy the word "monster" into lastmonst if the player is blind
900 1.5 christos * Enter with the coordinates (x,y) of the monster
901 1.5 christos * Returns no value.
902 1.1 cgd */
903 1.5 christos void
904 1.13 dholland ifblind(int x, int y)
905 1.5 christos {
906 1.13 dholland const char *p;
907 1.13 dholland
908 1.5 christos vxy(&x, &y); /* verify correct x,y coordinates */
909 1.5 christos if (c[BLINDCOUNT]) {
910 1.5 christos lastnum = 279;
911 1.5 christos p = "monster";
912 1.5 christos } else {
913 1.5 christos lastnum = mitem[x][y];
914 1.5 christos p = monster[lastnum].name;
915 1.1 cgd }
916 1.5 christos strcpy(lastmonst, p);
917 1.5 christos }
918 1.1 cgd
919 1.1 cgd /*
920 1.5 christos * tdirect(spnum) Routine to teleport away a monster
921 1.5 christos * int spnum;
922 1.1 cgd *
923 1.5 christos * Routine to ask for a direction to a spell and then teleport away monster
924 1.5 christos * Enter with the spell number that wants to teleport away
925 1.5 christos * Returns no value.
926 1.1 cgd */
927 1.5 christos void
928 1.1 cgd tdirect(spnum)
929 1.5 christos int spnum;
930 1.5 christos {
931 1.5 christos int x, y;
932 1.5 christos int m;
933 1.5 christos if (spnum < 0 || spnum >= SPNUM)
934 1.5 christos return; /* bad args */
935 1.5 christos if (isconfuse())
936 1.5 christos return;
937 1.5 christos dirsub(&x, &y);
938 1.5 christos if ((m = mitem[x][y]) == 0) {
939 1.5 christos lprcat(" There wasn't anything there!");
940 1.5 christos return;
941 1.1 cgd }
942 1.5 christos ifblind(x, y);
943 1.5 christos if (nospell(spnum, m)) {
944 1.5 christos lasthx = x;
945 1.5 christos lasthy = y;
946 1.5 christos return;
947 1.1 cgd }
948 1.5 christos fillmonst(m);
949 1.5 christos mitem[x][y] = know[x][y] = 0;
950 1.5 christos }
951 1.5 christos
952 1.5 christos /*
953 1.5 christos * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
954 1.5 christos * int sp,dam;
955 1.5 christos * char *str;
956 1.5 christos *
957 1.5 christos * Routine to cast a spell and then hit the monster in all directions
958 1.5 christos * Enter with the spell number in sp, the damage done to wach square in dam,
959 1.5 christos * and the lprintf string to identify the spell in str.
960 1.5 christos * Returns no value.
961 1.5 christos */
962 1.5 christos void
963 1.13 dholland omnidirect(int spnum, int dam, const char *str)
964 1.5 christos {
965 1.5 christos int x, y, m;
966 1.13 dholland
967 1.5 christos if (spnum < 0 || spnum >= SPNUM || str == 0)
968 1.5 christos return; /* bad args */
969 1.5 christos for (x = playerx - 1; x < playerx + 2; x++)
970 1.5 christos for (y = playery - 1; y < playery + 2; y++) {
971 1.6 veego if ((m = mitem[x][y]) != 0) {
972 1.5 christos if (nospell(spnum, m) == 0) {
973 1.5 christos ifblind(x, y);
974 1.5 christos cursors();
975 1.5 christos lprc('\n');
976 1.5 christos lprintf(str, lastmonst);
977 1.5 christos hitm(x, y, dam);
978 1.5 christos nap(800);
979 1.5 christos } else {
980 1.5 christos lasthx = x;
981 1.5 christos lasthy = y;
982 1.5 christos }
983 1.6 veego }
984 1.5 christos }
985 1.5 christos }
986 1.5 christos
987 1.5 christos /*
988 1.5 christos * static dirsub(x,y) Routine to ask for direction, then modify x,y for it
989 1.5 christos * int *x,*y;
990 1.5 christos *
991 1.5 christos * Function to ask for a direction and modify an x,y for that direction
992 1.5 christos * Enter with the origination coordinates in (x,y).
993 1.5 christos * Returns index into diroffx[] (0-8).
994 1.1 cgd */
995 1.1 cgd static int
996 1.5 christos dirsub(x, y)
997 1.5 christos int *x, *y;
998 1.5 christos {
999 1.5 christos int i;
1000 1.1 cgd lprcat("\nIn What Direction? ");
1001 1.5 christos for (i = 0;;)
1002 1.7 christos switch (lgetchar()) {
1003 1.5 christos case 'b':
1004 1.5 christos i++;
1005 1.5 christos case 'n':
1006 1.5 christos i++;
1007 1.5 christos case 'y':
1008 1.5 christos i++;
1009 1.5 christos case 'u':
1010 1.5 christos i++;
1011 1.5 christos case 'h':
1012 1.5 christos i++;
1013 1.5 christos case 'k':
1014 1.5 christos i++;
1015 1.5 christos case 'l':
1016 1.5 christos i++;
1017 1.5 christos case 'j':
1018 1.5 christos i++;
1019 1.5 christos goto out;
1020 1.5 christos };
1021 1.1 cgd out:
1022 1.5 christos *x = playerx + diroffx[i];
1023 1.5 christos *y = playery + diroffy[i];
1024 1.5 christos vxy(x, y);
1025 1.5 christos return (i);
1026 1.5 christos }
1027 1.5 christos
1028 1.5 christos /*
1029 1.5 christos * vxy(x,y) Routine to verify/fix coordinates for being within bounds
1030 1.5 christos * int *x,*y;
1031 1.5 christos *
1032 1.5 christos * Function to verify x & y are within the bounds for a level
1033 1.5 christos * If *x or *y is not within the absolute bounds for a level, fix them so that
1034 1.5 christos * they are on the level.
1035 1.5 christos * Returns TRUE if it was out of bounds, and the *x & *y in the calling
1036 1.5 christos * routine are affected.
1037 1.5 christos */
1038 1.5 christos int
1039 1.5 christos vxy(x, y)
1040 1.5 christos int *x, *y;
1041 1.5 christos {
1042 1.5 christos int flag = 0;
1043 1.5 christos if (*x < 0) {
1044 1.5 christos *x = 0;
1045 1.5 christos flag++;
1046 1.5 christos }
1047 1.5 christos if (*y < 0) {
1048 1.5 christos *y = 0;
1049 1.5 christos flag++;
1050 1.5 christos }
1051 1.5 christos if (*x >= MAXX) {
1052 1.5 christos *x = MAXX - 1;
1053 1.5 christos flag++;
1054 1.5 christos }
1055 1.5 christos if (*y >= MAXY) {
1056 1.5 christos *y = MAXY - 1;
1057 1.5 christos flag++;
1058 1.5 christos }
1059 1.5 christos return (flag);
1060 1.5 christos }
1061 1.5 christos
1062 1.5 christos /*
1063 1.5 christos * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
1064 1.5 christos * int spnum;
1065 1.5 christos *
1066 1.5 christos * Subroutine to polymorph a monster and ask for the direction its in
1067 1.5 christos * Enter with the spell number in spmun.
1068 1.5 christos * Returns no value.
1069 1.5 christos */
1070 1.5 christos void
1071 1.5 christos dirpoly(spnum)
1072 1.5 christos int spnum;
1073 1.5 christos {
1074 1.5 christos int x, y, m;
1075 1.5 christos if (spnum < 0 || spnum >= SPNUM)
1076 1.5 christos return; /* bad args */
1077 1.5 christos if (isconfuse())
1078 1.5 christos return; /* if he is confused, he can't aim his magic */
1079 1.5 christos dirsub(&x, &y);
1080 1.5 christos if (mitem[x][y] == 0) {
1081 1.5 christos lprcat(" There wasn't anything there!");
1082 1.5 christos return;
1083 1.1 cgd }
1084 1.5 christos ifblind(x, y);
1085 1.5 christos if (nospell(spnum, mitem[x][y])) {
1086 1.5 christos lasthx = x;
1087 1.5 christos lasthy = y;
1088 1.5 christos return;
1089 1.1 cgd }
1090 1.5 christos while (monster[m = mitem[x][y] = rnd(MAXMONST + 7)].genocided);
1091 1.1 cgd hitp[x][y] = monster[m].hitpoints;
1092 1.5 christos show1cell(x, y); /* show the new monster */
1093 1.5 christos }
1094 1.1 cgd
1095 1.1 cgd /*
1096 1.5 christos * hitmonster(x,y) Function to hit a monster at the designated coordinates
1097 1.5 christos * int x,y;
1098 1.1 cgd *
1099 1.5 christos * This routine is used for a bash & slash type attack on a monster
1100 1.5 christos * Enter with the coordinates of the monster in (x,y).
1101 1.5 christos * Returns no value.
1102 1.5 christos */
1103 1.5 christos void
1104 1.5 christos hitmonster(x, y)
1105 1.5 christos int x, y;
1106 1.5 christos {
1107 1.5 christos int tmp, monst, damag = 0, flag;
1108 1.5 christos if (c[TIMESTOP])
1109 1.5 christos return; /* not if time stopped */
1110 1.5 christos vxy(&x, &y); /* verify coordinates are within range */
1111 1.5 christos if ((monst = mitem[x][y]) == 0)
1112 1.5 christos return;
1113 1.5 christos hit3flag = 1;
1114 1.5 christos ifblind(x, y);
1115 1.5 christos tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] +
1116 1.5 christos c[WCLASS] / 4 - 12;
1117 1.1 cgd cursors();
1118 1.5 christos /* need at least random chance to hit */
1119 1.5 christos if ((rnd(20) < tmp - c[HARDGAME]) || (rnd(71) < 5)) {
1120 1.5 christos lprcat("\nYou hit");
1121 1.5 christos flag = 1;
1122 1.5 christos damag = fullhit(1);
1123 1.5 christos if (damag < 9999)
1124 1.5 christos damag = rnd(damag) + 1;
1125 1.5 christos } else {
1126 1.5 christos lprcat("\nYou missed");
1127 1.5 christos flag = 0;
1128 1.5 christos }
1129 1.5 christos lprcat(" the ");
1130 1.5 christos lprcat(lastmonst);
1131 1.5 christos if (flag) /* if the monster was hit */
1132 1.5 christos if ((monst == RUSTMONSTER) || (monst == DISENCHANTRESS) || (monst == CUBE))
1133 1.5 christos if (c[WIELD] > 0)
1134 1.5 christos if (ivenarg[c[WIELD]] > -10) {
1135 1.5 christos lprintf("\nYour weapon is dulled by the %s", lastmonst);
1136 1.5 christos beep();
1137 1.5 christos --ivenarg[c[WIELD]];
1138 1.5 christos }
1139 1.5 christos if (flag)
1140 1.5 christos hitm(x, y, damag);
1141 1.5 christos if (monst == VAMPIRE)
1142 1.5 christos if (hitp[x][y] < 25) {
1143 1.5 christos mitem[x][y] = BAT;
1144 1.5 christos know[x][y] = 0;
1145 1.5 christos }
1146 1.5 christos }
1147 1.5 christos
1148 1.5 christos /*
1149 1.5 christos * hitm(x,y,amt) Function to just hit a monster at a given coordinates
1150 1.5 christos * int x,y,amt;
1151 1.5 christos *
1152 1.5 christos * Returns the number of hitpoints the monster absorbed
1153 1.5 christos * This routine is used to specifically damage a monster at a location (x,y)
1154 1.5 christos * Called by hitmonster(x,y)
1155 1.5 christos */
1156 1.5 christos int
1157 1.5 christos hitm(x, y, amt)
1158 1.5 christos int x, y;
1159 1.5 christos int amt;
1160 1.5 christos {
1161 1.5 christos int monst;
1162 1.5 christos int hpoints, amt2;
1163 1.5 christos vxy(&x, &y); /* verify coordinates are within range */
1164 1.1 cgd amt2 = amt; /* save initial damage so we can return it */
1165 1.1 cgd monst = mitem[x][y];
1166 1.5 christos if (c[HALFDAM])
1167 1.5 christos amt >>= 1; /* if half damage curse adjust damage points */
1168 1.5 christos if (amt <= 0)
1169 1.5 christos amt2 = amt = 1;
1170 1.5 christos lasthx = x;
1171 1.5 christos lasthy = y;
1172 1.5 christos stealth[x][y] = 1; /* make sure hitting monst breaks stealth
1173 1.5 christos * condition */
1174 1.5 christos c[HOLDMONST] = 0; /* hit a monster breaks hold monster spell */
1175 1.5 christos switch (monst) { /* if a dragon and orb(s) of dragon slaying */
1176 1.5 christos case WHITEDRAGON:
1177 1.5 christos case REDDRAGON:
1178 1.5 christos case GREENDRAGON:
1179 1.5 christos case BRONZEDRAGON:
1180 1.5 christos case PLATINUMDRAGON:
1181 1.5 christos case SILVERDRAGON:
1182 1.5 christos amt *= 1 + (c[SLAYING] << 1);
1183 1.5 christos break;
1184 1.5 christos }
1185 1.5 christos /* invincible monster fix is here */
1186 1.1 cgd if (hitp[x][y] > monster[monst].hitpoints)
1187 1.1 cgd hitp[x][y] = monster[monst].hitpoints;
1188 1.5 christos if ((hpoints = hitp[x][y]) <= amt) {
1189 1.1 cgd #ifdef EXTRA
1190 1.1 cgd c[MONSTKILLED]++;
1191 1.1 cgd #endif
1192 1.5 christos lprintf("\nThe %s died!", lastmonst);
1193 1.5 christos raiseexperience((long) monster[monst].experience);
1194 1.5 christos amt = monster[monst].gold;
1195 1.5 christos if (amt > 0)
1196 1.5 christos dropgold(rnd(amt) + amt);
1197 1.5 christos dropsomething(monst);
1198 1.5 christos disappear(x, y);
1199 1.5 christos bottomline();
1200 1.5 christos return (hpoints);
1201 1.5 christos }
1202 1.5 christos hitp[x][y] = hpoints - amt;
1203 1.5 christos return (amt2);
1204 1.5 christos }
1205 1.5 christos
1206 1.5 christos /*
1207 1.5 christos * hitplayer(x,y) Function for the monster to hit the player from (x,y)
1208 1.5 christos * int x,y;
1209 1.5 christos *
1210 1.5 christos * Function for the monster to hit the player with monster at location x,y
1211 1.5 christos * Returns nothing of value.
1212 1.5 christos */
1213 1.5 christos void
1214 1.5 christos hitplayer(x, y)
1215 1.5 christos int x, y;
1216 1.5 christos {
1217 1.5 christos int dam, tmp, mster, bias;
1218 1.5 christos vxy(&x, &y); /* verify coordinates are within range */
1219 1.5 christos lastnum = mster = mitem[x][y];
1220 1.5 christos /*
1221 1.11 mouse * spirit nagas and poltergeists do nothing if scarab of negate
1222 1.5 christos * spirit
1223 1.5 christos */
1224 1.5 christos if (c[NEGATESPIRIT] || c[SPIRITPRO])
1225 1.5 christos if ((mster == POLTERGEIST) || (mster == SPIRITNAGA))
1226 1.5 christos return;
1227 1.5 christos /* if undead and cube of undead control */
1228 1.5 christos if (c[CUBEofUNDEAD] || c[UNDEADPRO])
1229 1.5 christos if ((mster == VAMPIRE) || (mster == WRAITH) || (mster == ZOMBIE))
1230 1.5 christos return;
1231 1.5 christos if ((know[x][y] & 1) == 0) {
1232 1.5 christos know[x][y] = 1;
1233 1.5 christos show1cell(x, y);
1234 1.1 cgd }
1235 1.1 cgd bias = (c[HARDGAME]) + 1;
1236 1.1 cgd hitflag = hit2flag = hit3flag = 1;
1237 1.5 christos yrepcount = 0;
1238 1.5 christos cursors();
1239 1.5 christos ifblind(x, y);
1240 1.5 christos if (c[INVISIBILITY])
1241 1.5 christos if (rnd(33) < 20) {
1242 1.5 christos lprintf("\nThe %s misses wildly", lastmonst);
1243 1.5 christos return;
1244 1.1 cgd }
1245 1.5 christos if (c[CHARMCOUNT])
1246 1.5 christos if (rnd(30) + 5 * monster[mster].level - c[CHARISMA] < 30) {
1247 1.5 christos lprintf("\nThe %s is awestruck at your magnificence!", lastmonst);
1248 1.5 christos return;
1249 1.1 cgd }
1250 1.5 christos if (mster == BAT)
1251 1.5 christos dam = 1;
1252 1.5 christos else {
1253 1.1 cgd dam = monster[mster].damage;
1254 1.5 christos dam += rnd((int) ((dam < 1) ? 1 : dam)) + monster[mster].level;
1255 1.5 christos }
1256 1.1 cgd tmp = 0;
1257 1.5 christos if (monster[mster].attack > 0)
1258 1.5 christos if (((dam + bias + 8) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) {
1259 1.5 christos if (spattack(monster[mster].attack, x, y)) {
1260 1.5 christos flushall();
1261 1.5 christos return;
1262 1.5 christos }
1263 1.5 christos tmp = 1;
1264 1.5 christos bias -= 2;
1265 1.5 christos cursors();
1266 1.5 christos }
1267 1.5 christos if (((dam + bias) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) {
1268 1.5 christos lprintf("\n The %s hit you ", lastmonst);
1269 1.5 christos tmp = 1;
1270 1.5 christos if ((dam -= c[AC]) < 0)
1271 1.5 christos dam = 0;
1272 1.5 christos if (dam > 0) {
1273 1.5 christos losehp(dam);
1274 1.5 christos bottomhp();
1275 1.5 christos flushall();
1276 1.5 christos }
1277 1.5 christos }
1278 1.5 christos if (tmp == 0)
1279 1.5 christos lprintf("\n The %s missed ", lastmonst);
1280 1.5 christos }
1281 1.5 christos
1282 1.5 christos /*
1283 1.5 christos * dropsomething(monst) Function to create an object when a monster dies
1284 1.5 christos * int monst;
1285 1.5 christos *
1286 1.5 christos * Function to create an object near the player when certain monsters are killed
1287 1.5 christos * Enter with the monster number
1288 1.5 christos * Returns nothing of value.
1289 1.1 cgd */
1290 1.14 dholland static void
1291 1.1 cgd dropsomething(monst)
1292 1.5 christos int monst;
1293 1.5 christos {
1294 1.5 christos switch (monst) {
1295 1.5 christos case ORC:
1296 1.5 christos case NYMPH:
1297 1.5 christos case ELF:
1298 1.5 christos case TROGLODYTE:
1299 1.5 christos case TROLL:
1300 1.5 christos case ROTHE:
1301 1.5 christos case VIOLETFUNGI:
1302 1.5 christos case PLATINUMDRAGON:
1303 1.5 christos case GNOMEKING:
1304 1.5 christos case REDDRAGON:
1305 1.5 christos something(level);
1306 1.5 christos return;
1307 1.1 cgd
1308 1.5 christos case LEPRECHAUN:
1309 1.5 christos if (rnd(101) >= 75)
1310 1.5 christos creategem();
1311 1.5 christos if (rnd(5) == 1)
1312 1.5 christos dropsomething(LEPRECHAUN);
1313 1.5 christos return;
1314 1.1 cgd }
1315 1.5 christos }
1316 1.1 cgd
1317 1.1 cgd /*
1318 1.5 christos * dropgold(amount) Function to drop some gold around player
1319 1.5 christos * int amount;
1320 1.1 cgd *
1321 1.5 christos * Enter with the number of gold pieces to drop
1322 1.5 christos * Returns nothing of value.
1323 1.1 cgd */
1324 1.5 christos void
1325 1.1 cgd dropgold(amount)
1326 1.5 christos int amount;
1327 1.5 christos {
1328 1.5 christos if (amount > 250)
1329 1.5 christos createitem(OMAXGOLD, amount / 100);
1330 1.5 christos else
1331 1.5 christos createitem(OGOLDPILE, amount);
1332 1.5 christos }
1333 1.1 cgd
1334 1.1 cgd /*
1335 1.5 christos * something(level) Function to create a random item around player
1336 1.5 christos * int level;
1337 1.1 cgd *
1338 1.5 christos * Function to create an item from a designed probability around player
1339 1.5 christos * Enter with the cave level on which something is to be dropped
1340 1.5 christos * Returns nothing of value.
1341 1.1 cgd */
1342 1.5 christos void
1343 1.13 dholland something(int cavelevel)
1344 1.5 christos {
1345 1.5 christos int j;
1346 1.5 christos int i;
1347 1.13 dholland if (cavelevel < 0 || cavelevel > MAXLEVEL + MAXVLEVEL)
1348 1.5 christos return; /* correct level? */
1349 1.5 christos if (rnd(101) < 8)
1350 1.13 dholland something(cavelevel); /* possibly more than one item */
1351 1.13 dholland j = newobject(cavelevel, &i);
1352 1.5 christos createitem(j, i);
1353 1.5 christos }
1354 1.5 christos
1355 1.5 christos /*
1356 1.5 christos * newobject(lev,i) Routine to return a randomly selected new object
1357 1.5 christos * int lev,*i;
1358 1.5 christos *
1359 1.5 christos * Routine to return a randomly selected object to be created
1360 1.5 christos * Returns the object number created, and sets *i for its argument
1361 1.5 christos * Enter with the cave level and a pointer to the items arg
1362 1.5 christos */
1363 1.5 christos static char nobjtab[] = {
1364 1.5 christos 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION, OPOTION,
1365 1.5 christos OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE,
1366 1.5 christos OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER,
1367 1.5 christos OLEATHER, OLEATHER, OLEATHER, OREGENRING, OPROTRING,
1368 1.5 christos OENERGYRING, ODEXRING, OSTRRING, OSPEAR, OBELT, ORING,
1369 1.5 christos OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
1370 1.5 christos OLONGSWORD};
1371 1.5 christos
1372 1.5 christos int
1373 1.5 christos newobject(lev, i)
1374 1.5 christos int lev, *i;
1375 1.5 christos {
1376 1.5 christos int tmp = 32, j;
1377 1.5 christos if (level < 0 || level > MAXLEVEL + MAXVLEVEL)
1378 1.5 christos return (0); /* correct level? */
1379 1.5 christos if (lev > 6)
1380 1.5 christos tmp = 37;
1381 1.5 christos else if (lev > 4)
1382 1.5 christos tmp = 35;
1383 1.5 christos j = nobjtab[tmp = rnd(tmp)]; /* the object type */
1384 1.5 christos switch (tmp) {
1385 1.5 christos case 1:
1386 1.5 christos case 2:
1387 1.5 christos case 3:
1388 1.5 christos case 4:
1389 1.5 christos *i = newscroll();
1390 1.5 christos break;
1391 1.5 christos case 5:
1392 1.5 christos case 6:
1393 1.5 christos case 7:
1394 1.5 christos case 8:
1395 1.5 christos *i = newpotion();
1396 1.5 christos break;
1397 1.5 christos case 9:
1398 1.5 christos case 10:
1399 1.5 christos case 11:
1400 1.5 christos case 12:
1401 1.5 christos *i = rnd((lev + 1) * 10) + lev * 10 + 10;
1402 1.5 christos break;
1403 1.5 christos case 13:
1404 1.5 christos case 14:
1405 1.5 christos case 15:
1406 1.5 christos case 16:
1407 1.5 christos *i = lev;
1408 1.5 christos break;
1409 1.5 christos case 17:
1410 1.5 christos case 18:
1411 1.5 christos case 19:
1412 1.5 christos if (!(*i = newdagger()))
1413 1.5 christos return (0);
1414 1.5 christos break;
1415 1.5 christos case 20:
1416 1.5 christos case 21:
1417 1.5 christos case 22:
1418 1.5 christos if (!(*i = newleather()))
1419 1.5 christos return (0);
1420 1.5 christos break;
1421 1.5 christos case 23:
1422 1.5 christos case 32:
1423 1.5 christos case 35:
1424 1.5 christos *i = rund(lev / 3 + 1);
1425 1.5 christos break;
1426 1.5 christos case 24:
1427 1.5 christos case 26:
1428 1.5 christos *i = rnd(lev / 4 + 1);
1429 1.5 christos break;
1430 1.5 christos case 25:
1431 1.5 christos *i = rund(lev / 4 + 1);
1432 1.5 christos break;
1433 1.5 christos case 27:
1434 1.5 christos *i = rnd(lev / 2 + 1);
1435 1.5 christos break;
1436 1.5 christos case 30:
1437 1.5 christos case 33:
1438 1.5 christos *i = rund(lev / 2 + 1);
1439 1.5 christos break;
1440 1.5 christos case 28:
1441 1.5 christos *i = rund(lev / 3 + 1);
1442 1.5 christos if (*i == 0)
1443 1.5 christos return (0);
1444 1.5 christos break;
1445 1.5 christos case 29:
1446 1.5 christos case 31:
1447 1.5 christos *i = rund(lev / 2 + 1);
1448 1.5 christos if (*i == 0)
1449 1.5 christos return (0);
1450 1.5 christos break;
1451 1.5 christos case 34:
1452 1.5 christos *i = newchain();
1453 1.5 christos break;
1454 1.5 christos case 36:
1455 1.5 christos *i = newplate();
1456 1.5 christos break;
1457 1.5 christos case 37:
1458 1.5 christos *i = newsword();
1459 1.5 christos break;
1460 1.1 cgd }
1461 1.5 christos return (j);
1462 1.5 christos }
1463 1.1 cgd
1464 1.1 cgd /*
1465 1.5 christos * spattack(atckno,xx,yy) Function to process special attacks from monsters
1466 1.1 cgd * int atckno,xx,yy;
1467 1.1 cgd *
1468 1.5 christos * Enter with the special attack number, and the coordinates (xx,yy)
1469 1.5 christos * of the monster that is special attacking
1470 1.5 christos * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
1471 1.1 cgd *
1472 1.1 cgd * atckno monster effect
1473 1.1 cgd * ---------------------------------------------------
1474 1.5 christos * 0 none
1475 1.5 christos * 1 rust monster eat armor
1476 1.5 christos * 2 hell hound breathe light fire
1477 1.5 christos * 3 dragon breathe fire
1478 1.5 christos * 4 giant centipede weakening sing
1479 1.5 christos * 5 white dragon cold breath
1480 1.5 christos * 6 wraith drain level
1481 1.5 christos * 7 waterlord water gusher
1482 1.5 christos * 8 leprechaun steal gold
1483 1.5 christos * 9 disenchantress disenchant weapon or armor
1484 1.5 christos * 10 ice lizard hits with barbed tail
1485 1.5 christos * 11 umber hulk confusion
1486 1.5 christos * 12 spirit naga cast spells taken from special attacks
1487 1.5 christos * 13 platinum dragon psionics
1488 1.5 christos * 14 nymph steal objects
1489 1.5 christos * 15 bugbear bite
1490 1.5 christos * 16 osequip bite
1491 1.5 christos *
1492 1.5 christos * char rustarm[ARMORTYPES][2];
1493 1.5 christos * special array for maximum rust damage to armor from rustmonster
1494 1.5 christos * format is: { armor type , minimum attribute
1495 1.1 cgd */
1496 1.1 cgd #define ARMORTYPES 6
1497 1.5 christos static char rustarm[ARMORTYPES][2] = {
1498 1.5 christos { OSTUDLEATHER, -2 },
1499 1.5 christos { ORING, -4 },
1500 1.5 christos { OCHAIN, -5 },
1501 1.5 christos { OSPLINT, -6 },
1502 1.5 christos { OPLATE, -8 },
1503 1.5 christos { OPLATEARMOR, -9}
1504 1.5 christos };
1505 1.5 christos static char spsel[] = {1, 2, 3, 5, 6, 8, 9, 11, 13, 14};
1506 1.14 dholland static int
1507 1.5 christos spattack(x, xx, yy)
1508 1.5 christos int x, xx, yy;
1509 1.5 christos {
1510 1.5 christos int i, j = 0, k, m;
1511 1.13 dholland const char *p = NULL;
1512 1.13 dholland
1513 1.5 christos if (c[CANCELLATION])
1514 1.5 christos return (0);
1515 1.5 christos vxy(&xx, &yy); /* verify x & y coordinates */
1516 1.5 christos switch (x) {
1517 1.5 christos case 1: /* rust your armor, j=1 when rusting has occurred */
1518 1.5 christos m = k = c[WEAR];
1519 1.6 veego if ((i = c[SHIELD]) != -1) {
1520 1.5 christos if (--ivenarg[i] < -1)
1521 1.5 christos ivenarg[i] = -1;
1522 1.5 christos else
1523 1.5 christos j = 1;
1524 1.6 veego }
1525 1.5 christos if ((j == 0) && (k != -1)) {
1526 1.5 christos m = iven[k];
1527 1.5 christos for (i = 0; i < ARMORTYPES; i++)
1528 1.5 christos /* find his armor in table */
1529 1.5 christos if (m == rustarm[i][0]) {
1530 1.5 christos if (--ivenarg[k] < rustarm[i][1])
1531 1.5 christos ivenarg[k] = rustarm[i][1];
1532 1.5 christos else
1533 1.5 christos j = 1;
1534 1.5 christos break;
1535 1.5 christos }
1536 1.5 christos }
1537 1.5 christos if (j == 0) /* if rusting did not occur */
1538 1.5 christos switch (m) {
1539 1.5 christos case OLEATHER:
1540 1.11 mouse p = "\nThe %s hit you -- You're lucky you have leather on";
1541 1.1 cgd break;
1542 1.5 christos case OSSPLATE:
1543 1.11 mouse p = "\nThe %s hit you -- You're fortunate to have stainless steel armor!";
1544 1.1 cgd break;
1545 1.5 christos }
1546 1.5 christos else {
1547 1.5 christos beep();
1548 1.5 christos p = "\nThe %s hit you -- your armor feels weaker";
1549 1.5 christos }
1550 1.5 christos break;
1551 1.5 christos
1552 1.5 christos case 2:
1553 1.5 christos i = rnd(15) + 8 - c[AC];
1554 1.5 christos spout: p = "\nThe %s breathes fire at you!";
1555 1.5 christos if (c[FIRERESISTANCE])
1556 1.11 mouse p = "\nThe %s's flame doesn't faze you!";
1557 1.5 christos else
1558 1.5 christos spout2: if (p) {
1559 1.5 christos lprintf(p, lastmonst);
1560 1.5 christos beep();
1561 1.5 christos }
1562 1.5 christos checkloss(i);
1563 1.5 christos return (0);
1564 1.5 christos
1565 1.5 christos case 3:
1566 1.5 christos i = rnd(20) + 25 - c[AC];
1567 1.5 christos goto spout;
1568 1.5 christos
1569 1.5 christos case 4:
1570 1.5 christos if (c[STRENGTH] > 3) {
1571 1.5 christos p = "\nThe %s stung you! You feel weaker";
1572 1.5 christos beep();
1573 1.5 christos --c[STRENGTH];
1574 1.5 christos } else
1575 1.5 christos p = "\nThe %s stung you!";
1576 1.5 christos break;
1577 1.5 christos
1578 1.5 christos case 5:
1579 1.5 christos p = "\nThe %s blasts you with his cold breath";
1580 1.5 christos i = rnd(15) + 18 - c[AC];
1581 1.5 christos goto spout2;
1582 1.5 christos
1583 1.5 christos case 6:
1584 1.5 christos lprintf("\nThe %s drains you of your life energy!", lastmonst);
1585 1.5 christos loselevel();
1586 1.5 christos beep();
1587 1.5 christos return (0);
1588 1.5 christos
1589 1.5 christos case 7:
1590 1.5 christos p = "\nThe %s got you with a gusher!";
1591 1.5 christos i = rnd(15) + 25 - c[AC];
1592 1.5 christos goto spout2;
1593 1.5 christos
1594 1.5 christos case 8:
1595 1.5 christos if (c[NOTHEFT])
1596 1.5 christos return (0); /* he has a device of no theft */
1597 1.5 christos if (c[GOLD]) {
1598 1.5 christos p = "\nThe %s hit you -- Your purse feels lighter";
1599 1.5 christos if (c[GOLD] > 32767)
1600 1.5 christos c[GOLD] >>= 1;
1601 1.5 christos else
1602 1.5 christos c[GOLD] -= rnd((int) (1 + (c[GOLD] >> 1)));
1603 1.5 christos if (c[GOLD] < 0)
1604 1.5 christos c[GOLD] = 0;
1605 1.5 christos } else
1606 1.5 christos p = "\nThe %s couldn't find any gold to steal";
1607 1.5 christos lprintf(p, lastmonst);
1608 1.5 christos disappear(xx, yy);
1609 1.5 christos beep();
1610 1.5 christos bottomgold();
1611 1.5 christos return (1);
1612 1.5 christos
1613 1.5 christos case 9:
1614 1.5 christos for (j = 50;;) {/* disenchant */
1615 1.5 christos i = rund(26);
1616 1.5 christos m = iven[i]; /* randomly select item */
1617 1.5 christos if (m > 0 && ivenarg[i] > 0 && m != OSCROLL && m != OPOTION) {
1618 1.5 christos if ((ivenarg[i] -= 3) < 0)
1619 1.5 christos ivenarg[i] = 0;
1620 1.5 christos lprintf("\nThe %s hits you -- you feel a sense of loss", lastmonst);
1621 1.5 christos srcount = 0;
1622 1.5 christos beep();
1623 1.5 christos show3(i);
1624 1.5 christos bottomline();
1625 1.5 christos return (0);
1626 1.5 christos }
1627 1.5 christos if (--j <= 0) {
1628 1.5 christos p = "\nThe %s nearly misses";
1629 1.1 cgd break;
1630 1.5 christos }
1631 1.5 christos break;
1632 1.5 christos }
1633 1.5 christos break;
1634 1.1 cgd
1635 1.5 christos case 10:
1636 1.5 christos p = "\nThe %s hit you with his barbed tail";
1637 1.5 christos i = rnd(25) - c[AC];
1638 1.5 christos goto spout2;
1639 1.5 christos
1640 1.5 christos case 11:
1641 1.5 christos p = "\nThe %s has confused you";
1642 1.5 christos beep();
1643 1.5 christos c[CONFUSE] += 10 + rnd(10);
1644 1.5 christos break;
1645 1.5 christos
1646 1.5 christos case 12: /* performs any number of other special
1647 1.5 christos * attacks */
1648 1.5 christos return (spattack(spsel[rund(10)], xx, yy));
1649 1.5 christos
1650 1.5 christos case 13:
1651 1.5 christos p = "\nThe %s flattens you with his psionics!";
1652 1.5 christos i = rnd(15) + 30 - c[AC];
1653 1.5 christos goto spout2;
1654 1.5 christos
1655 1.5 christos case 14:
1656 1.5 christos if (c[NOTHEFT])
1657 1.5 christos return (0); /* he has device of no theft */
1658 1.5 christos if (emptyhanded() == 1) {
1659 1.5 christos p = "\nThe %s couldn't find anything to steal";
1660 1.5 christos break;
1661 1.5 christos }
1662 1.5 christos lprintf("\nThe %s picks your pocket and takes:", lastmonst);
1663 1.5 christos beep();
1664 1.5 christos if (stealsomething() == 0)
1665 1.5 christos lprcat(" nothing");
1666 1.5 christos disappear(xx, yy);
1667 1.5 christos bottomline();
1668 1.5 christos return (1);
1669 1.5 christos
1670 1.5 christos case 15:
1671 1.5 christos i = rnd(10) + 5 - c[AC];
1672 1.5 christos spout3: p = "\nThe %s bit you!";
1673 1.5 christos goto spout2;
1674 1.5 christos
1675 1.5 christos case 16:
1676 1.5 christos i = rnd(15) + 10 - c[AC];
1677 1.5 christos goto spout3;
1678 1.5 christos };
1679 1.5 christos if (p) {
1680 1.5 christos lprintf(p, lastmonst);
1681 1.5 christos bottomline();
1682 1.1 cgd }
1683 1.5 christos return (0);
1684 1.5 christos }
1685 1.1 cgd
1686 1.1 cgd /*
1687 1.5 christos * checkloss(x) Routine to subtract hp from user and flag bottomline display
1688 1.5 christos * int x;
1689 1.1 cgd *
1690 1.5 christos * Routine to subtract hitpoints from the user and flag the bottomline display
1691 1.5 christos * Enter with the number of hit points to lose
1692 1.5 christos * Note: if x > c[HP] this routine could kill the player!
1693 1.1 cgd */
1694 1.5 christos void
1695 1.1 cgd checkloss(x)
1696 1.5 christos int x;
1697 1.5 christos {
1698 1.5 christos if (x > 0) {
1699 1.5 christos losehp(x);
1700 1.5 christos bottomhp();
1701 1.1 cgd }
1702 1.5 christos }
1703 1.1 cgd
1704 1.1 cgd /*
1705 1.5 christos * annihilate() Routine to annihilate all monsters around player (playerx,playery)
1706 1.1 cgd *
1707 1.5 christos * Gives player experience, but no dropped objects
1708 1.5 christos * Returns the experience gained from all monsters killed
1709 1.1 cgd */
1710 1.5 christos int
1711 1.1 cgd annihilate()
1712 1.5 christos {
1713 1.5 christos int i, j;
1714 1.5 christos long k;
1715 1.5 christos u_char *p;
1716 1.5 christos for (k = 0, i = playerx - 1; i <= playerx + 1; i++)
1717 1.5 christos for (j = playery - 1; j <= playery + 1; j++)
1718 1.6 veego if (!vxy(&i, &j)) { /* if not out of bounds */
1719 1.6 veego if (*(p = &mitem[i][j])) { /* if a monster there */
1720 1.5 christos if (*p < DEMONLORD + 2) {
1721 1.5 christos k += monster[*p].experience;
1722 1.5 christos *p = know[i][j] = 0;
1723 1.5 christos } else {
1724 1.5 christos lprintf("\nThe %s barely escapes being annihilated!", monster[*p].name);
1725 1.5 christos hitp[i][j] = (hitp[i][j] >> 1) + 1; /* lose half hit points */
1726 1.1 cgd }
1727 1.6 veego }
1728 1.6 veego }
1729 1.5 christos if (k > 0) {
1730 1.5 christos lprcat("\nYou hear loud screams of agony!");
1731 1.5 christos raiseexperience((long) k);
1732 1.5 christos }
1733 1.5 christos return (k);
1734 1.5 christos }
1735 1.5 christos
1736 1.5 christos /*
1737 1.5 christos * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
1738 1.5 christos * int x,y,dir,lifetime;
1739 1.5 christos *
1740 1.5 christos * Enter with the coordinates of the sphere in x,y
1741 1.5 christos * the direction (0-8 diroffx format) in dir, and the lifespan of the
1742 1.5 christos * sphere in lifetime (in turns)
1743 1.5 christos * Returns the number of spheres currently in existence
1744 1.5 christos */
1745 1.5 christos int
1746 1.5 christos newsphere(x, y, dir, life)
1747 1.5 christos int x, y, dir, life;
1748 1.5 christos {
1749 1.5 christos int m;
1750 1.5 christos struct sphere *sp;
1751 1.5 christos if (((sp = (struct sphere *) malloc(sizeof(struct sphere)))) == 0)
1752 1.5 christos return (c[SPHCAST]); /* can't malloc, therefore failure */
1753 1.5 christos if (dir >= 9)
1754 1.5 christos dir = 0; /* no movement if direction not found */
1755 1.5 christos if (level == 0)
1756 1.5 christos vxy(&x, &y); /* don't go out of bounds */
1757 1.5 christos else {
1758 1.5 christos if (x < 1)
1759 1.5 christos x = 1;
1760 1.5 christos if (x >= MAXX - 1)
1761 1.5 christos x = MAXX - 2;
1762 1.5 christos if (y < 1)
1763 1.5 christos y = 1;
1764 1.5 christos if (y >= MAXY - 1)
1765 1.5 christos y = MAXY - 2;
1766 1.5 christos }
1767 1.5 christos if ((m = mitem[x][y]) >= DEMONLORD + 4) { /* demons dispel spheres */
1768 1.5 christos know[x][y] = 1;
1769 1.5 christos show1cell(x, y);/* show the demon (ha ha) */
1770 1.5 christos cursors();
1771 1.5 christos lprintf("\nThe %s dispels the sphere!", monster[m].name);
1772 1.5 christos beep();
1773 1.5 christos rmsphere(x, y); /* remove any spheres that are here */
1774 1.10 christos free(sp);
1775 1.5 christos return (c[SPHCAST]);
1776 1.5 christos }
1777 1.5 christos if (m == DISENCHANTRESS) { /* disenchantress cancels spheres */
1778 1.5 christos cursors();
1779 1.5 christos lprintf("\nThe %s causes cancellation of the sphere!", monster[m].name);
1780 1.5 christos beep();
1781 1.5 christos boom: sphboom(x, y); /* blow up stuff around sphere */
1782 1.5 christos rmsphere(x, y); /* remove any spheres that are here */
1783 1.10 christos free(sp);
1784 1.5 christos return (c[SPHCAST]);
1785 1.1 cgd }
1786 1.5 christos if (c[CANCELLATION]) { /* cancellation cancels spheres */
1787 1.5 christos cursors();
1788 1.5 christos lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!");
1789 1.5 christos beep();
1790 1.1 cgd goto boom;
1791 1.5 christos }
1792 1.5 christos if (item[x][y] == OANNIHILATION) { /* collision of spheres
1793 1.5 christos * detonates spheres */
1794 1.5 christos cursors();
1795 1.5 christos lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!");
1796 1.5 christos beep();
1797 1.5 christos rmsphere(x, y);
1798 1.1 cgd goto boom;
1799 1.5 christos }
1800 1.5 christos if (playerx == x && playery == y) { /* collision of sphere and
1801 1.5 christos * player! */
1802 1.1 cgd cursors();
1803 1.1 cgd lprcat("\nYou have been enveloped by the zone of nothingness!\n");
1804 1.5 christos beep();
1805 1.5 christos rmsphere(x, y); /* remove any spheres that are here */
1806 1.5 christos nap(4000);
1807 1.5 christos died(258);
1808 1.5 christos }
1809 1.5 christos item[x][y] = OANNIHILATION;
1810 1.5 christos mitem[x][y] = 0;
1811 1.5 christos know[x][y] = 1;
1812 1.5 christos show1cell(x, y); /* show the new sphere */
1813 1.5 christos sp->x = x;
1814 1.5 christos sp->y = y;
1815 1.5 christos sp->lev = level;
1816 1.5 christos sp->dir = dir;
1817 1.5 christos sp->lifetime = life;
1818 1.5 christos sp->p = 0;
1819 1.5 christos if (spheres == 0)
1820 1.5 christos spheres = sp; /* if first node in the sphere list */
1821 1.5 christos else { /* add sphere to beginning of linked list */
1822 1.5 christos sp->p = spheres;
1823 1.5 christos spheres = sp;
1824 1.5 christos }
1825 1.5 christos return (++c[SPHCAST]); /* one more sphere in the world */
1826 1.5 christos }
1827 1.5 christos
1828 1.5 christos /*
1829 1.5 christos * rmsphere(x,y) Function to delete a sphere of annihilation from list
1830 1.5 christos * int x,y;
1831 1.5 christos *
1832 1.5 christos * Enter with the coordinates of the sphere (on current level)
1833 1.5 christos * Returns the number of spheres currently in existence
1834 1.5 christos */
1835 1.5 christos int
1836 1.5 christos rmsphere(x, y)
1837 1.5 christos int x, y;
1838 1.5 christos {
1839 1.5 christos struct sphere *sp, *sp2 = 0;
1840 1.5 christos for (sp = spheres; sp; sp2 = sp, sp = sp->p)
1841 1.5 christos if (level == sp->lev) /* is sphere on this level? */
1842 1.5 christos if ((x == sp->x) && (y == sp->y)) { /* locate sphere at this
1843 1.5 christos * location */
1844 1.5 christos item[x][y] = mitem[x][y] = 0;
1845 1.5 christos know[x][y] = 1;
1846 1.5 christos show1cell(x, y); /* show the now missing
1847 1.5 christos * sphere */
1848 1.5 christos --c[SPHCAST];
1849 1.5 christos if (sp == spheres) {
1850 1.5 christos sp2 = sp;
1851 1.5 christos spheres = sp->p;
1852 1.5 christos free((char *) sp2);
1853 1.5 christos } else {
1854 1.9 christos if (sp2)
1855 1.9 christos sp2->p = sp->p;
1856 1.5 christos free((char *) sp);
1857 1.5 christos }
1858 1.5 christos break;
1859 1.1 cgd }
1860 1.5 christos return (c[SPHCAST]); /* return number of spheres in the world */
1861 1.5 christos }
1862 1.1 cgd
1863 1.1 cgd /*
1864 1.5 christos * sphboom(x,y) Function to perform the effects of a sphere detonation
1865 1.5 christos * int x,y;
1866 1.1 cgd *
1867 1.5 christos * Enter with the coordinates of the blast, Returns no value
1868 1.1 cgd */
1869 1.5 christos void
1870 1.5 christos sphboom(x, y)
1871 1.5 christos int x, y;
1872 1.5 christos {
1873 1.5 christos int i, j;
1874 1.5 christos if (c[HOLDMONST])
1875 1.5 christos c[HOLDMONST] = 1;
1876 1.5 christos if (c[CANCELLATION])
1877 1.5 christos c[CANCELLATION] = 1;
1878 1.5 christos for (j = max(1, x - 2); j < min(x + 3, MAXX - 1); j++)
1879 1.5 christos for (i = max(1, y - 2); i < min(y + 3, MAXY - 1); i++) {
1880 1.5 christos item[j][i] = mitem[j][i] = 0;
1881 1.5 christos show1cell(j, i);
1882 1.5 christos if (playerx == j && playery == i) {
1883 1.5 christos cursors();
1884 1.5 christos beep();
1885 1.5 christos lprcat("\nYou were too close to the sphere!");
1886 1.5 christos nap(3000);
1887 1.5 christos died(283); /* player killed in explosion */
1888 1.1 cgd }
1889 1.1 cgd }
1890 1.5 christos }
1891 1.1 cgd
1892 1.1 cgd /*
1893 1.5 christos * genmonst() Function to ask for monster and genocide from game
1894 1.1 cgd *
1895 1.5 christos * This is done by setting a flag in the monster[] structure
1896 1.1 cgd */
1897 1.5 christos void
1898 1.1 cgd genmonst()
1899 1.5 christos {
1900 1.5 christos int i, j;
1901 1.5 christos cursors();
1902 1.5 christos lprcat("\nGenocide what monster? ");
1903 1.7 christos for (i = 0; (!isalpha(i)) && (i != ' '); i = lgetchar());
1904 1.1 cgd lprc(i);
1905 1.5 christos for (j = 0; j < MAXMONST; j++) /* search for the monster type */
1906 1.5 christos if (monstnamelist[j] == i) { /* have we found it? */
1907 1.5 christos monster[j].genocided = 1; /* genocided from game */
1908 1.5 christos lprintf(" There will be no more %s's", monster[j].name);
1909 1.1 cgd /* now wipe out monsters on this level */
1910 1.5 christos newcavelevel(level);
1911 1.5 christos draws(0, MAXX, 0, MAXY);
1912 1.5 christos bot_linex();
1913 1.1 cgd return;
1914 1.5 christos }
1915 1.1 cgd lprcat(" You sense failure!");
1916 1.5 christos }
1917