OSDN Git Service

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