OSDN Git Service

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