1    | /*	SCCS Id: @(#)worm.c	3.3	95/01/28	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | #include "lev.h"
7    | 
8    | #define newseg()		(struct wseg *) alloc(sizeof(struct wseg))
9    | #define dealloc_seg(wseg)	free((genericptr_t) (wseg))
10   | 
11   | /* worm segment structure */
12   | struct wseg {
13   |     struct wseg *nseg;
14   |     xchar  wx, wy;	/* the segment's position */
15   | };
16   | 
17   | STATIC_DCL void FDECL(toss_wsegs, (struct wseg *,BOOLEAN_P));
18   | STATIC_DCL void FDECL(shrink_worm, (int));
19   | STATIC_DCL void FDECL(random_dir, (XCHAR_P,XCHAR_P,xchar *,xchar *));
20   | STATIC_DCL struct wseg *FDECL(create_worm_tail, (int));
21   | 
22   | /*  Description of long worm implementation.
23   |  *
24   |  *  Each monst struct of the head of a tailed worm has a wormno set to
25   |  *			1 <= wormno < MAX_NUM_WORMS
26   |  *  If wormno == 0 this does not mean that the monster is not a worm,
27   |  *  it just means that the monster does not have a long worm tail.
28   |  *
29   |  *  The actual segments of a worm are not full blown monst structs.
30   |  *  They are small wseg structs, and their position in the levels.monsters[][]
31   |  *  array is held by the monst struct of the head of the worm.  This makes
32   |  *  things like probing and hit point bookkeeping much easier.
33   |  *
34   |  *  The segments of the long worms on a level are kept as an array of
35   |  *  singly threaded linked lists.  The wormno variable is used as an index
36   |  *  for these segment arrays.
37   |  *
38   |  *  wtails:	The first (starting struct) of a linked list.  This points
39   |  *		to the tail (last) segment of the worm.
40   |  *
41   |  *  wheads:	The last (end) of a linked list of segments.  This points to
42   |  *		the segment that is at the same position as the real monster
43   |  *		(the head).  Note that the segment that wheads[wormno] points
44   |  *		to, is not displayed.  It is simply there to keep track of
45   |  *		where the head came from, so that worm movement and display are
46   |  *		simplified later.
47   |  *		Keeping the head segment of the worm at the end of the list
48   |  *		of tail segments is an endless source of confusion, but it is
49   |  *		necessary.
50   |  *		From now on, we will use "start" and "end" to refer to the
51   |  *		linked list and "head" and "tail" to refer to the worm.
52   |  *
53   |  *  One final worm array is:
54   |  *
55   |  *  wgrowtime:	This tells us when to add another segment to the worm.
56   |  *
57   |  *  When a worm is moved, we add a new segment at the head, and delete the
58   |  *  segment at the tail (unless we want it to grow).  This new head segment is
59   |  *  located in the same square as the actual head of the worm.  If we want
60   |  *  to grow the worm, we don't delete the tail segment, and we give the worm
61   |  *  extra hit points, which possibly go into its maximum.
62   |  *
63   |  *  Non-moving worms (worm_nomove) are assumed to be surrounded by their own
64   |  *  tail, and, thus, shrink instead of grow (as their tails keep going while
65   |  *  their heads are stopped short).  In this case, we delete the last tail
66   |  *  segment, and remove hit points from the worm.
67   |  */
68   | 
69   | struct wseg *wheads[MAX_NUM_WORMS]   = DUMMY, *wtails[MAX_NUM_WORMS] = DUMMY;
70   | long	    wgrowtime[MAX_NUM_WORMS] = DUMMY;
71   | 
72   | /*
73   |  *  get_wormno()
74   |  *
75   |  *  Find an unused worm tail slot and return the index.  A zero means that
76   |  *  there are no slots available.  This means that the worm head can exist,
77   |  *  it just cannot ever grow a tail.
78   |  *
79   |  *  It, also, means that there is an optimisation to made.  The [0] positions
80   |  *  of the arrays are never used.  Meaning, we really *could* have one more
81   |  *  tailed worm on the level, or use a smaller array (using wormno - 1).
82   |  *
83   |  *  Implementation is left to the interested hacker.
84   |  */
85   | int
86   | get_wormno()
87   | {
88   |     register int new_wormno = 1;
89   | 
90   |     while (new_wormno < MAX_NUM_WORMS) {
91   | 	if (!wheads[new_wormno])
92   | 	    return new_wormno; /* found an empty wtails[] slot at new_wormno */
93   | 	new_wormno++;
94   |     }
95   | 
96   |     return(0);	/* level infested with worms */
97   | }
98   | 
99   | /*
100  |  *  initworm()
101  |  *
102  |  *  Use if (mon->wormno = get_wormno()) before calling this function!
103  |  *
104  |  *  Initialize the worm entry.  This will set up the worm grow time, and
105  |  *  create and initialize the dummy segment for wheads[] and wtails[].
106  |  *
107  |  *  If the worm has no tail (ie get_wormno() fails) then this function need
108  |  *  not be called.
109  |  */
110  | void
111  | initworm(worm, wseg_count)
112  |     struct monst *worm;
113  |     int wseg_count;
114  | {
115  |     register struct wseg *seg, *new_tail = create_worm_tail(wseg_count);
116  |     register int wnum = worm->wormno;
117  | 
118  | /*  if (!wnum) return;  bullet proofing */
119  | 
120  |     if (new_tail) {
121  | 	wtails[wnum] = new_tail;
122  | 	for (seg = new_tail; seg->nseg; seg = seg->nseg);
123  | 	wheads[wnum] = seg;
124  |     } else {
125  | 	wtails[wnum] = wheads[wnum] = seg = newseg();
126  | 	seg->nseg    = (struct wseg *) 0;
127  | 	seg->wx      = worm->mx;
128  | 	seg->wy      = worm->my;
129  |     }
130  |     wgrowtime[wnum] = 0L;
131  | }
132  | 
133  | 
134  | /*
135  |  *  toss_wsegs()
136  |  *
137  |  *  Get rid of all worm segments on and following the given pointer curr.
138  |  *  The display may or may not need to be updated as we free the segments.
139  |  */
140  | STATIC_OVL
141  | void
142  | toss_wsegs(curr, display_update)
143  |     register struct wseg *curr;
144  |     register boolean display_update;
145  | {
146  |     register struct wseg *seg;
147  | 
148  |     while (curr) {
149  | 	seg = curr->nseg;
150  | 
151  | 	/* remove from level.monsters[][] */
152  | 
153  | 	/* need to check curr->wx for genocided while migrating_mon */
154  | 	if (curr->wx) {
155  | 	    remove_monster(curr->wx, curr->wy);
156  | 
157  | 	    /* update screen before deallocation */
158  | 	    if (display_update) newsym(curr->wx,curr->wy);
159  | 	}
160  | 
161  | 	/* free memory used by the segment */
162  | 	dealloc_seg(curr);
163  | 	curr = seg;
164  |     }
165  | }
166  | 
167  | 
168  | /*
169  |  *  shrink_worm()
170  |  *
171  |  *  Remove the tail segment of the worm (the starting segment of the list).
172  |  */
173  | STATIC_OVL
174  | void
175  | shrink_worm(wnum)
176  |     int wnum;	/* worm number */
177  | {
178  |     struct wseg *seg;
179  | 
180  |     if (wtails[wnum] == wheads[wnum]) return;	/* no tail */
181  | 
182  |     seg = wtails[wnum];
183  |     wtails[wnum] = seg->nseg;
184  |     seg->nseg = (struct wseg *) 0;
185  |     toss_wsegs(seg, TRUE);
186  | }
187  | 
188  | /*
189  |  *  worm_move()
190  |  *
191  |  *  Check for mon->wormno before calling this function!
192  |  *
193  |  *  Move the worm.  Maybe grow.
194  |  */
195  | void
196  | worm_move(worm)
197  |     struct monst *worm;
198  | {
199  |     register struct wseg *seg, *new_seg;	/* new segment */
200  |     register int	 wnum = worm->wormno;	/* worm number */
201  | 
202  | 
203  | /*  if (!wnum) return;  bullet proofing */
204  | 
205  |     /*
206  |      *  Place a segment at the old worm head.  The head has already moved.
207  |      */
208  |     seg = wheads[wnum];
209  |     place_worm_seg(worm, seg->wx, seg->wy);
210  |     newsym(seg->wx,seg->wy);		/* display the new segment */
211  | 
212  |     /*
213  |      *  Create a new dummy segment head and place it at the end of the list.
214  |      */
215  |     new_seg       = newseg();
216  |     new_seg->wx   = worm->mx;
217  |     new_seg->wy   = worm->my;
218  |     new_seg->nseg = (struct wseg *) 0;
219  |     seg->nseg     = new_seg;		/* attach it to the end of the list */
220  |     wheads[wnum]  = new_seg;		/* move the end pointer */
221  | 
222  | 
223  |     if (wgrowtime[wnum] <= moves) {
224  | 	if (!wgrowtime[wnum])
225  | 	    wgrowtime[wnum] = moves + rnd(5);
226  | 	else
227  | 	    wgrowtime[wnum] += rn1(15, 3);
228  | 	worm->mhp += 3;
229  | 	if (worm->mhp > MHPMAX) worm->mhp = MHPMAX;
230  | 	if (worm->mhp > worm->mhpmax) worm->mhpmax = worm->mhp;
231  |     } else
232  | 	/* The worm doesn't grow, so the last segment goes away. */
233  | 	shrink_worm(wnum);
234  | }
235  | 
236  | /*
237  |  *  worm_nomove()
238  |  *
239  |  *  Check for mon->wormno before calling this function!
240  |  *
241  |  *  The worm don't move so it should shrink.
242  |  */
243  | void
244  | worm_nomove(worm)
245  |     register struct monst *worm;
246  | {
247  |     shrink_worm((int) worm->wormno);	/* shrink */
248  | 
249  |     if (worm->mhp > 3)
250  | 	worm->mhp -= 3;		/* mhpmax not changed ! */
251  |     else
252  | 	worm->mhp = 1;
253  | }
254  | 
255  | /*
256  |  *  wormgone()
257  |  *
258  |  *  Check for mon->wormno before calling this function!
259  |  *
260  |  *  Kill a worm tail.
261  |  */
262  | void
263  | wormgone(worm)
264  |     register struct monst *worm;
265  | {
266  |     register int wnum = worm->wormno;
267  | 
268  | /*  if (!wnum) return;  bullet proofing */
269  | 
270  |     worm->wormno = 0;
271  | 
272  |     /*  This will also remove the real monster (ie 'w') from the its
273  |      *  position in level.monsters[][].
274  |      */
275  |     toss_wsegs(wtails[wnum], TRUE);
276  | 
277  |     wheads[wnum] = wtails[wnum] = (struct wseg *) 0;
278  | }
279  | 
280  | /*
281  |  *  wormhitu()
282  |  *
283  |  *  Check for mon->wormno before calling this function!
284  |  *
285  |  *  If the hero is near any part of the worm, the worm will try to attack.
286  |  */
287  | void
288  | wormhitu(worm)
289  |     register struct monst *worm;
290  | {
291  |     register int wnum = worm->wormno;
292  |     register struct wseg *seg;
293  | 
294  | /*  if (!wnum) return;  bullet proofing */
295  | 
296  | /*  This does not work right now because mattacku() thinks that the head is
297  |  *  out of range of the player.  We might try to kludge, and bring the head
298  |  *  within range for a tiny moment, but this needs a bit more looking at
299  |  *  before we decide to do this.
300  |  */
301  |     for (seg = wtails[wnum]; seg; seg = seg->nseg)
302  | 	if (distu(seg->wx, seg->wy) < 3)
303  | 	    (void) mattacku(worm);
304  | }
305  | 
306  | /*  cutworm()
307  |  *
308  |  *  Check for mon->wormno before calling this function!
309  |  *
310  |  *  When hitting a worm (worm) at position x, y, with a weapon (weap),
311  |  *  there is a chance that the worm will be cut in half, and a chance
312  |  *  that both halves will survive.
313  |  */
314  | void
315  | cutworm(worm, x, y, weap)
316  |     struct monst *worm;
317  |     xchar x,y;
318  |     struct obj *weap;
319  | {
320  |     register struct wseg  *curr, *new_tail;
321  |     register struct monst *new_worm;
322  |     int wnum = worm->wormno;
323  |     int cut_chance, new_wnum;
324  | 
325  |     if (!wnum) return; /* bullet proofing */
326  | 
327  |     if (x == worm->mx && y == worm->my) return;		/* hit on head */
328  | 
329  |     /* cutting goes best with a bladed weapon */
330  |     cut_chance = rnd(20);	/* Normally  1-16 does not cut */
331  | 				/* Normally 17-20 does */
332  | 
333  |     if (weap && is_blade(weap))	/* With a blade 1- 6 does not cut */
334  | 	cut_chance += 10;	/*		7-20 does */
335  | 
336  |     if (cut_chance < 17) return;	/* not good enough */
337  | 
338  |     /* Find the segment that was attacked. */
339  |     curr = wtails[wnum];
340  | 
341  |     while ( (curr->wx != x) || (curr->wy != y) ) {
342  | 	curr = curr->nseg;
343  | 	if (!curr) {
344  | 	    impossible("cut_worm:  no segment at (%d,%d)", (int) x, (int) y);
345  | 	    return;
346  | 	}
347  |     }
348  | 
349  |     /* If this is the tail segment, then the worm just loses it. */
350  |     if (curr == wtails[wnum]) {
351  | 	shrink_worm(wnum);
352  | 	return;
353  |     }
354  | 
355  |     /*
356  |      *  Split the worm.  The tail for the new worm is the old worm's tail.
357  |      *  The tail for the old worm is the segment that follows "curr",
358  |      *  and "curr" becomes the dummy segment under the new head.
359  |      */
360  |     new_tail = wtails[wnum];
361  |     wtails[wnum] = curr->nseg;
362  |     curr->nseg = (struct wseg *) 0;	/* split the worm */
363  | 
364  |     /*
365  |      *  At this point, the old worm is correct.  Any new worm will have
366  |      *  it's head at "curr" and its tail at "new_tail".
367  |      */
368  | 
369  |     /* Sometimes the tail end dies. */
370  |     if (rn2(3) || !(new_wnum = get_wormno())) {
371  | 	You("cut part of the tail off of %s.", mon_nam(worm));
372  | 	toss_wsegs(new_tail, TRUE);
373  | 	if (worm->mhp > 1) worm->mhp /= 2;
374  | 	return;
375  |     }
376  | 
377  |     /* Create the second worm. */
378  |     new_worm  = newmonst(0);
379  |     *new_worm = *worm;			/* make a copy of the old worm */
380  |     new_worm->m_id = flags.ident++;	/* make sure it has a unique id */
381  |     new_worm->wormno = new_wnum;	/* affix new worm number */
382  | 
383  |     if (worm->mtame)
384  | 	new_worm->mtame = (rn2(max(2 + u.uluck, 2)) ? worm->mtame : 0);
385  |     else
386  | 	if (worm->mpeaceful)
387  | 	    new_worm->mpeaceful = (rn2(max(2 + u.uluck, 2)) ? 1 : 0);
388  |     set_malign(new_worm);
389  | 
390  |     new_worm->mxlth = new_worm->mnamelth = 0;
391  | 
392  |     /* Devalue the monster level of both halves of the worm. */
393  |     worm->m_lev = ((unsigned)worm->m_lev <= 3) ?
394  | 		   (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
395  |     new_worm->m_lev = worm->m_lev;
396  | 
397  |     /* Calculate the mhp on the new_worm for the (lower) monster level. */
398  |     new_worm->mhpmax = new_worm->mhp = d((int)new_worm->m_lev, 8);
399  | 
400  |     /* Calculate the mhp on the old worm for the (lower) monster level. */
401  |     if (worm->m_lev > 3) {
402  | 	worm->mhpmax = d((int)worm->m_lev, 8);
403  | 	if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
404  |     }
405  | 
406  |     /* Add new monster to mon chain. */
407  |     new_worm->nmon = fmon;
408  |     fmon = new_worm;
409  | 
410  |     /* Initialize the new worm. */
411  |     place_monster(new_worm, x, y);	/* put worm in level.monsters[][] */
412  |     newsym(x, y);			/* make sure new worm shows up */
413  | 
414  |     wtails[new_wnum] = new_tail;	/* We've got all the info right now */
415  |     wheads[new_wnum] = curr;		/* so we can do this faster than    */
416  |     wgrowtime[new_wnum] = 0L;		/* trying to call initworm().       */
417  | 
418  |     /* Place the new monster at all the segment locations. */
419  |     place_wsegs(new_worm);
420  | 
421  | #if 0	/* long worms don't glow in the dark... */
422  |     if (emits_light(worm->data))
423  | 	new_light_source(new_worm->mx, new_worm->my,
424  | 			 emits_light(worm->data),
425  | 			 LS_MONSTER, (genericptr_t)new_worm);
426  | #endif
427  | 
428  |     You("cut %s in half.", mon_nam(worm));
429  | }
430  | 
431  | 
432  | /*
433  |  *  see_wsegs()
434  |  *
435  |  *  Refresh all of the segments of the given worm.  This is only called
436  |  *  from see_monster() in display.c or when a monster goes minvis.  It
437  |  *  is located here for modularity.
438  |  */
439  | void
440  | see_wsegs(worm)
441  |     struct monst *worm;
442  | {
443  |     struct wseg *curr = wtails[worm->wormno];
444  | 
445  | /*  if (!mtmp->wormno) return;  bullet proofing */
446  | 
447  |     while (curr != wheads[worm->wormno]) {
448  | 	newsym(curr->wx,curr->wy);
449  | 	curr = curr->nseg;
450  |     }
451  | }
452  | 
453  | 
454  | /*
455  |  *  save_worm()
456  |  *
457  |  *  Save the worm information for later use.  The count is the number
458  |  *  of segments, including the dummy.  Called from save.c.
459  |  */
460  | void
461  | save_worm(fd, mode)
462  |     int fd, mode;
463  | {
464  |     int i;
465  |     int count;
466  |     struct wseg *curr, *temp;
467  | 
468  |     if (perform_bwrite(mode)) {
469  | 	for (i = 1; i < MAX_NUM_WORMS; i++) {
470  | 	    for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++;
471  | 	    /* Save number of segments */
472  | 	    bwrite(fd, (genericptr_t) &count, sizeof(int));
473  | 	    /* Save segment locations of the monster. */
474  | 	    if (count) {
475  | 		for (curr = wtails[i]; curr; curr = curr->nseg) {
476  | 		    bwrite(fd, (genericptr_t) &(curr->wx), sizeof(xchar));
477  | 		    bwrite(fd, (genericptr_t) &(curr->wy), sizeof(xchar));
478  | 		}
479  | 	    }
480  | 	}
481  | 	bwrite(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
482  |     }
483  | 
484  |     if (release_data(mode)) {
485  | 	/* Free the segments only.  savemonchn() will take care of the
486  | 	 * monsters. */
487  | 	for (i = 1; i < MAX_NUM_WORMS; i++) {
488  | 	    if (!(curr = wtails[i])) continue;
489  | 
490  | 	    while (curr) {
491  | 		temp = curr->nseg;
492  | 		dealloc_seg(curr);		/* free the segment */
493  | 		curr = temp;
494  | 	    }
495  | 	    wheads[i] = wtails[i] = (struct wseg *) 0;
496  | 	}
497  |     }
498  | 
499  | }
500  | 
501  | /*
502  |  *  rest_worm()
503  |  *
504  |  *  Restore the worm information from the save file.  Called from restore.c
505  |  */
506  | void
507  | rest_worm(fd)
508  |     int fd;
509  | {
510  |     int i, j, count;
511  |     struct wseg *curr, *temp;
512  | 
513  |     for (i = 1; i < MAX_NUM_WORMS; i++) {
514  | 	mread(fd, (genericptr_t) &count, sizeof(int));
515  | 	if (!count) continue;	/* none */
516  | 
517  | 	/* Get the segments. */
518  | 	for (curr = (struct wseg *) 0, j = 0; j < count; j++) {
519  | 	    temp = newseg();
520  | 	    temp->nseg = (struct wseg *) 0;
521  | 	    mread(fd, (genericptr_t) &(temp->wx), sizeof(xchar));
522  | 	    mread(fd, (genericptr_t) &(temp->wy), sizeof(xchar));
523  | 	    if (curr)
524  | 		curr->nseg = temp;
525  | 	    else
526  | 		wtails[i] = temp;
527  | 	    curr = temp;
528  | 	}
529  | 	wheads[i] = curr;
530  |     }
531  |     mread(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
532  | }
533  | 
534  | /*
535  |  *  place_wsegs()
536  |  *
537  |  *  Place the segments of the given worm.  Called from restore.c
538  |  */
539  | void
540  | place_wsegs(worm)
541  |     struct monst *worm;
542  | {
543  |     struct wseg *curr = wtails[worm->wormno];
544  | 
545  | /*  if (!mtmp->wormno) return;  bullet proofing */
546  | 
547  |     while (curr != wheads[worm->wormno]) {
548  | 	place_worm_seg(worm,curr->wx,curr->wy);
549  | 	curr = curr->nseg;
550  |     }
551  | }
552  | 
553  | /*
554  |  *  remove_worm()
555  |  *
556  |  *  This function is equivalent to the remove_monster #define in
557  |  *  rm.h, only it will take the worm *and* tail out of the levels array.
558  |  *  It does not get rid of (dealloc) the worm tail structures, and it does
559  |  *  not remove the mon from the fmon chain.
560  |  */
561  | void
562  | remove_worm(worm)
563  |     register struct monst *worm;
564  | {
565  |     register struct wseg *curr = wtails[worm->wormno];
566  | 
567  | /*  if (!mtmp->wormno) return;  bullet proofing */
568  | 
569  |     while (curr) {
570  | 	remove_monster(curr->wx, curr->wy);
571  | 	newsym(curr->wx, curr->wy);
572  | 	curr = curr->nseg;
573  |     }
574  | }
575  | 
576  | /*
577  |  *  place_worm_tail_randomly()
578  |  *
579  |  *  Place a worm tail somewhere on a level behind the head.
580  |  *  This routine essentially reverses the order of the wsegs from head
581  |  *  to tail while placing them.
582  |  *  x, and y are most likely the worm->mx, and worm->my, but don't *need* to
583  |  *  be, if somehow the head is disjoint from the tail.
584  |  */
585  | void
586  | place_worm_tail_randomly(worm, x, y)
587  |     struct monst *worm;
588  |     xchar x, y;
589  | {
590  |     int wnum = worm->wormno;
591  |     struct wseg *curr = wtails[wnum];
592  |     struct wseg *new_tail;
593  |     register xchar ox = x, oy = y;
594  | 
595  | /*  if (!wnum) return;  bullet proofing */
596  | 
597  |     if (wnum && (!wtails[wnum] || !wheads[wnum]) ) {
598  | 	impossible("place_worm_tail_randomly: wormno is set without a tail!");
599  | 	return;
600  |     }
601  | 
602  |     wheads[wnum] = new_tail = curr;
603  |     curr = curr->nseg;
604  |     new_tail->nseg = (struct wseg *) 0;
605  |     new_tail->wx = x;
606  |     new_tail->wy = y;
607  | 
608  |     while(curr)  {
609  | 	xchar nx, ny;
610  | 	char tryct = 0;
611  | 
612  | 	/* pick a random direction from x, y and search for goodpos() */
613  | 
614  | 	do {
615  | 	    random_dir(ox, oy, &nx, &ny);
616  | 	} while (!goodpos(nx, ny, worm) && (tryct++ < 50));
617  | 
618  | 	if (tryct < 50)  {
619  | 	    place_worm_seg(worm, nx, ny);
620  | 	    curr->wx = ox = nx;
621  | 	    curr->wy = oy = ny;
622  | 	    wtails[wnum] = curr;
623  | 	    curr = curr->nseg;
624  | 	    wtails[wnum]->nseg = new_tail;
625  | 	    new_tail = wtails[wnum];
626  | 	    newsym(nx, ny);
627  | 	} else {			/* Oops.  Truncate because there was */
628  | 	    toss_wsegs(curr, FALSE);    /* no place for the rest of it */
629  | 	    curr = (struct wseg *) 0;
630  | 	}
631  |     }
632  | }
633  | 
634  | /*
635  |  * Given a coordinate x, y.
636  |  * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining.
637  |  *
638  |  * This function, and the loop it serves, could be eliminated by coding
639  |  * enexto() with a search radius.
640  |  */
641  | STATIC_OVL
642  | void
643  | random_dir(x, y, nx, ny)
644  |     register xchar   x,   y;
645  |     register xchar *nx, *ny;
646  | {
647  |     *nx = x;
648  |     *ny = y;
649  | 
650  |     *nx += (x > 1 ?			/* extreme left ? */
651  | 		(x < COLNO ?		 /* extreme right ? */
652  | 			(rn2(3) - 1)	  /* neither so +1, 0, or -1 */
653  | 		:	-rn2(2))	 /* 0, or -1 */
654  | 	   :	rn2(2));		/* 0, or 1 */
655  | 
656  |     *ny += (*nx == x ?			/* same kind of thing with y */
657  | 		(y > 1 ?
658  | 		    (y < ROWNO ?
659  | 			(rn2(2) ?
660  | 			    1
661  | 			:   -1)
662  | 		    :	-1)
663  | 		:   1)
664  | 	    :	(y > 1 ?
665  | 		    (y < ROWNO ?
666  | 			(rn2(3) - 1)
667  | 		    :	-rn2(2))
668  | 		:   rn2(2)));
669  | }
670  | 
671  | /*  count_wsegs()
672  |  *
673  |  *  returns
674  |  *  the number of visible segments that a worm has.
675  |  */
676  | 
677  | int
678  | count_wsegs(mtmp)
679  |     struct monst *mtmp;
680  | {
681  |     register int i=0;
682  |     register struct wseg *curr = (wtails[mtmp->wormno])->nseg;
683  | 
684  | /*  if (!mtmp->wormno) return 0;  bullet proofing */
685  | 
686  |     while (curr) {
687  | 	i++;
688  | 	curr = curr->nseg;
689  |     }
690  | 
691  |     return i;
692  | }
693  | 
694  | /*  create_worm_tail()
695  |  *
696  |  *  will create a worm tail chain of (num_segs + 1) and return a pointer to it.
697  |  */
698  | STATIC_OVL
699  | struct wseg *
700  | create_worm_tail(num_segs)
701  |     int num_segs;
702  | {
703  |     register int i=0;
704  |     register struct wseg *new_tail, *curr;
705  | 
706  |     if (!num_segs) return (struct wseg *)0;
707  | 
708  |     new_tail = curr = newseg();
709  |     curr->nseg = (struct wseg *)0;
710  |     curr->wx = 0;
711  |     curr->wy = 0;
712  | 
713  |     while (i < num_segs) {
714  | 	curr->nseg = newseg();
715  | 	curr = curr->nseg;
716  | 	curr->nseg = (struct wseg *)0;
717  | 	curr->wx = 0;
718  | 	curr->wy = 0;
719  | 	i++;
720  |     }
721  | 
722  |     return (new_tail);
723  | }
724  | 
725  | /*  worm_known()
726  |  *
727  |  *  Is any segment of this worm in viewing range?  Note: caller must check
728  |  *  invisibility and telepathy (which should only show the head anyway).
729  |  *  Mostly used in the canseemon() macro.
730  |  */
731  | boolean
732  | worm_known(worm)
733  | struct monst *worm;
734  | {
735  |     struct wseg *curr = wtails[worm->wormno];
736  | 
737  |     while (curr) {
738  | 	if(cansee(curr->wx,curr->wy)) return TRUE;
739  | 	curr = curr->nseg;
740  |     }
741  |     return FALSE;
742  | }
743  | 
744  | /*worm.c*/