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*/