OSDN Git Service

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