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 /* NetHack may be freely redistributed. See license for details. */
8 #define newseg() (struct wseg *) alloc(sizeof (struct wseg))
9 #define dealloc_seg(wseg) free((genericptr_t) (wseg))
11 /* worm segment structure */
14 xchar wx
, wy
; /* the segment's position */
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));
22 /* Description of long worm implementation.
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.
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.
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.
38 * wtails: The first (starting struct) of a linked list. This points
39 * to the tail (last) segment of the worm.
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
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.
53 * One final worm array is:
55 * wgrowtime: This tells us when to add another segment to the worm.
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.
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.
69 struct wseg
*wheads
[MAX_NUM_WORMS
] = DUMMY
, *wtails
[MAX_NUM_WORMS
] = DUMMY
;
70 long wgrowtime
[MAX_NUM_WORMS
] = DUMMY
;
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.
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).
83 * Implementation is left to the interested hacker.
88 register int new_wormno
= 1;
90 while (new_wormno
< MAX_NUM_WORMS
) {
91 if (!wheads
[new_wormno
])
92 return new_wormno
; /* found empty wtails[] slot at new_wormno */
95 return 0; /* level infested with worms */
101 * Use if (mon->wormno = get_wormno()) before calling this function!
103 * Initialize the worm entry. This will set up the worm grow time, and
104 * create and initialize the dummy segment for wheads[] and wtails[].
106 * If the worm has no tail (ie get_wormno() fails) then this function need
110 initworm(worm
, wseg_count
)
114 register struct wseg
*seg
, *new_tail
= create_worm_tail(wseg_count
);
115 register int wnum
= worm
->wormno
;
117 /* if (!wnum) return; bullet proofing */
120 wtails
[wnum
] = new_tail
;
121 for (seg
= new_tail
; seg
->nseg
; seg
= seg
->nseg
)
125 wtails
[wnum
] = wheads
[wnum
] = seg
= newseg();
126 seg
->nseg
= (struct wseg
*) 0;
130 wgrowtime
[wnum
] = 0L;
136 * Get rid of all worm segments on and following the given pointer curr.
137 * The display may or may not need to be updated as we free the segments.
141 toss_wsegs(curr
, display_update
)
142 register struct wseg
*curr
;
143 register boolean display_update
;
145 register struct wseg
*seg
;
150 /* remove from level.monsters[][] */
152 /* need to check curr->wx for genocided while migrating_mon */
154 remove_monster(curr
->wx
, curr
->wy
);
156 /* update screen before deallocation */
158 newsym(curr
->wx
, curr
->wy
);
161 /* free memory used by the segment */
170 * Remove the tail segment of the worm (the starting segment of the list).
175 int wnum
; /* worm number */
179 if (wtails
[wnum
] == wheads
[wnum
])
180 return; /* no tail */
183 wtails
[wnum
] = seg
->nseg
;
184 seg
->nseg
= (struct wseg
*) 0;
185 toss_wsegs(seg
, TRUE
);
191 * Check for mon->wormno before calling this function!
193 * Move the worm. Maybe grow.
199 register struct wseg
*seg
, *new_seg
; /* new segment */
200 register int wnum
= worm
->wormno
; /* worm number */
202 /* if (!wnum) return; bullet proofing */
205 * Place a segment at the old worm head. The head has already moved.
208 place_worm_seg(worm
, seg
->wx
, seg
->wy
);
209 newsym(seg
->wx
, seg
->wy
); /* display the new segment */
212 * Create a new dummy segment head and place it at the end of the list.
215 new_seg
->wx
= worm
->mx
;
216 new_seg
->wy
= worm
->my
;
217 new_seg
->nseg
= (struct wseg
*) 0;
218 seg
->nseg
= new_seg
; /* attach it to the end of the list */
219 wheads
[wnum
] = new_seg
; /* move the end pointer */
221 if (wgrowtime
[wnum
] <= moves
) {
222 if (!wgrowtime
[wnum
])
223 wgrowtime
[wnum
] = moves
+ rnd(5);
225 wgrowtime
[wnum
] += rn1(15, 3);
227 if (worm
->mhp
> MHPMAX
)
229 if (worm
->mhp
> worm
->mhpmax
)
230 worm
->mhpmax
= worm
->mhp
;
232 /* The worm doesn't grow, so the last segment goes away. */
239 * Check for mon->wormno before calling this function!
241 * The worm don't move so it should shrink.
245 register struct monst
*worm
;
247 shrink_worm((int) worm
->wormno
); /* shrink */
250 worm
->mhp
-= 3; /* mhpmax not changed ! */
258 * Check for mon->wormno before calling this function!
264 register struct monst
*worm
;
266 register int wnum
= worm
->wormno
;
268 /* if (!wnum) return; bullet proofing */
272 /* This will also remove the real monster (ie 'w') from the its
273 * position in level.monsters[][].
275 toss_wsegs(wtails
[wnum
], TRUE
);
277 wheads
[wnum
] = wtails
[wnum
] = (struct wseg
*) 0;
283 * Check for mon->wormno before calling this function!
285 * If the hero is near any part of the worm, the worm will try to attack.
289 register struct monst
*worm
;
291 register int wnum
= worm
->wormno
;
292 register struct wseg
*seg
;
294 /* if (!wnum) return; bullet proofing */
296 /* This does not work right now because mattacku() thinks that the head
297 * is out of range of the player. We might try to kludge, and bring
298 * the head within range for a tiny moment, but this needs a bit more
299 * looking at before we decide to do this.
301 for (seg
= wtails
[wnum
]; seg
; seg
= seg
->nseg
)
302 if (distu(seg
->wx
, seg
->wy
) < 3)
303 (void) mattacku(worm
);
308 * Check for mon->wormno before calling this function!
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.
315 cutworm(worm
, x
, y
, weap
)
320 register struct wseg
*curr
, *new_tail
;
321 register struct monst
*new_worm
;
322 int wnum
= worm
->wormno
;
323 int cut_chance
, new_wnum
;
326 return; /* bullet proofing */
328 if (x
== worm
->mx
&& y
== worm
->my
)
329 return; /* hit on head */
331 /* cutting goes best with a bladed weapon */
332 cut_chance
= rnd(20); /* Normally 1-16 does not cut */
333 /* Normally 17-20 does */
335 if (weap
&& is_blade(weap
)) /* With a blade 1- 6 does not cut */
336 cut_chance
+= 10; /* 7-20 does */
339 return; /* not good enough */
341 /* Find the segment that was attacked. */
344 while ((curr
->wx
!= x
) || (curr
->wy
!= y
)) {
347 impossible("cutworm: no segment at (%d,%d)", (int) x
, (int) y
);
352 /* If this is the tail segment, then the worm just loses it. */
353 if (curr
== wtails
[wnum
]) {
359 * Split the worm. The tail for the new worm is the old worm's tail.
360 * The tail for the old worm is the segment that follows "curr",
361 * and "curr" becomes the dummy segment under the new head.
363 new_tail
= wtails
[wnum
];
364 wtails
[wnum
] = curr
->nseg
;
365 curr
->nseg
= (struct wseg
*) 0; /* split the worm */
368 * At this point, the old worm is correct. Any new worm will have
369 * it's head at "curr" and its tail at "new_tail". The old worm
370 * must be at least level 3 in order to produce a new worm.
373 new_wnum
= (worm
->m_lev
>= 3 && !rn2(3)) ? get_wormno() : 0;
375 remove_monster(x
, y
); /* clone_mon puts new head here */
376 /* clone_mon() will fail if enough long worms have been
377 created to have them be marked as extinct or if the hit
378 that cut the current one has dropped it down to 1 HP */
379 new_worm
= clone_mon(worm
, x
, y
);
382 /* Sometimes the tail end dies. */
384 if (context
.mon_moving
) {
385 if (canspotmon(worm
))
386 pline("Part of %s tail has been cut off.",
387 s_suffix(mon_nam(worm
)));
389 You("cut part of the tail off of %s.", mon_nam(worm
));
390 toss_wsegs(new_tail
, TRUE
);
396 new_worm
->wormno
= new_wnum
; /* affix new worm number */
397 new_worm
->mcloned
= 0; /* treat second worm as a normal monster */
399 /* Devalue the monster level of both halves of the worm.
400 Note: m_lev is always at least 3 in order to get this far. */
401 worm
->m_lev
= max((unsigned) worm
->m_lev
- 2, 3);
402 new_worm
->m_lev
= worm
->m_lev
;
404 /* Calculate the lower-level mhp; use <N>d8 for long worms.
405 Can't use newmonhp() here because it would reset m_lev. */
406 new_worm
->mhpmax
= new_worm
->mhp
= d((int) new_worm
->m_lev
, 8);
407 worm
->mhpmax
= d((int) worm
->m_lev
, 8); /* new maxHP for old worm */
408 if (worm
->mhpmax
< worm
->mhp
)
409 worm
->mhp
= worm
->mhpmax
;
411 wtails
[new_wnum
] = new_tail
; /* We've got all the info right now */
412 wheads
[new_wnum
] = curr
; /* so we can do this faster than */
413 wgrowtime
[new_wnum
] = 0L; /* trying to call initworm(). */
415 /* Place the new monster at all the segment locations. */
416 place_wsegs(new_worm
);
418 if (context
.mon_moving
)
419 pline("%s is cut in half.", Monnam(worm
));
421 You("cut %s in half.", mon_nam(worm
));
427 * Refresh all of the segments of the given worm. This is only called
428 * from see_monster() in display.c or when a monster goes minvis. It
429 * is located here for modularity.
435 struct wseg
*curr
= wtails
[worm
->wormno
];
437 /* if (!mtmp->wormno) return; bullet proofing */
439 while (curr
!= wheads
[worm
->wormno
]) {
440 newsym(curr
->wx
, curr
->wy
);
448 * Display all of the segments of the given worm for detection.
451 detect_wsegs(worm
, use_detection_glyph
)
453 boolean use_detection_glyph
;
456 struct wseg
*curr
= wtails
[worm
->wormno
];
458 /* if (!mtmp->wormno) return; bullet proofing */
460 while (curr
!= wheads
[worm
->wormno
]) {
461 num
= use_detection_glyph
462 ? detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL
))
464 ? petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL
))
465 : monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL
)));
466 show_glyph(curr
->wx
, curr
->wy
, num
);
474 * Save the worm information for later use. The count is the number
475 * of segments, including the dummy. Called from save.c.
483 struct wseg
*curr
, *temp
;
485 if (perform_bwrite(mode
)) {
486 for (i
= 1; i
< MAX_NUM_WORMS
; i
++) {
487 for (count
= 0, curr
= wtails
[i
]; curr
; curr
= curr
->nseg
)
489 /* Save number of segments */
490 bwrite(fd
, (genericptr_t
) &count
, sizeof(int));
491 /* Save segment locations of the monster. */
493 for (curr
= wtails
[i
]; curr
; curr
= curr
->nseg
) {
494 bwrite(fd
, (genericptr_t
) & (curr
->wx
), sizeof(xchar
));
495 bwrite(fd
, (genericptr_t
) & (curr
->wy
), sizeof(xchar
));
499 bwrite(fd
, (genericptr_t
) wgrowtime
, sizeof(wgrowtime
));
502 if (release_data(mode
)) {
503 /* Free the segments only. savemonchn() will take care of the
505 for (i
= 1; i
< MAX_NUM_WORMS
; i
++) {
506 if (!(curr
= wtails
[i
]))
511 dealloc_seg(curr
); /* free the segment */
514 wheads
[i
] = wtails
[i
] = (struct wseg
*) 0;
522 * Restore the worm information from the save file. Called from restore.c
529 struct wseg
*curr
, *temp
;
531 for (i
= 1; i
< MAX_NUM_WORMS
; i
++) {
532 mread(fd
, (genericptr_t
) &count
, sizeof(int));
536 /* Get the segments. */
537 for (curr
= (struct wseg
*) 0, j
= 0; j
< count
; j
++) {
539 temp
->nseg
= (struct wseg
*) 0;
540 mread(fd
, (genericptr_t
) & (temp
->wx
), sizeof(xchar
));
541 mread(fd
, (genericptr_t
) & (temp
->wy
), sizeof(xchar
));
550 mread(fd
, (genericptr_t
) wgrowtime
, sizeof(wgrowtime
));
556 * Place the segments of the given worm. Called from restore.c
562 struct wseg
*curr
= wtails
[worm
->wormno
];
564 /* if (!mtmp->wormno) return; bullet proofing */
566 while (curr
!= wheads
[worm
->wormno
]) {
567 place_worm_seg(worm
, curr
->wx
, curr
->wy
);
575 * This function is equivalent to the remove_monster #define in
576 * rm.h, only it will take the worm *and* tail out of the levels array.
577 * It does not get rid of (dealloc) the worm tail structures, and it does
578 * not remove the mon from the fmon chain.
582 register struct monst
*worm
;
584 register struct wseg
*curr
= wtails
[worm
->wormno
];
586 /* if (!mtmp->wormno) return; bullet proofing */
589 remove_monster(curr
->wx
, curr
->wy
);
590 newsym(curr
->wx
, curr
->wy
);
596 * place_worm_tail_randomly()
598 * Place a worm tail somewhere on a level behind the head.
599 * This routine essentially reverses the order of the wsegs from head
600 * to tail while placing them.
601 * x, and y are most likely the worm->mx, and worm->my, but don't *need* to
602 * be, if somehow the head is disjoint from the tail.
605 place_worm_tail_randomly(worm
, x
, y
)
609 int wnum
= worm
->wormno
;
610 struct wseg
*curr
= wtails
[wnum
];
611 struct wseg
*new_tail
;
612 register xchar ox
= x
, oy
= y
;
614 /* if (!wnum) return; bullet proofing */
616 if (wnum
&& (!wtails
[wnum
] || !wheads
[wnum
])) {
617 impossible("place_worm_tail_randomly: wormno is set without a tail!");
621 wheads
[wnum
] = new_tail
= curr
;
623 new_tail
->nseg
= (struct wseg
*) 0;
631 /* pick a random direction from x, y and search for goodpos() */
634 random_dir(ox
, oy
, &nx
, &ny
);
635 } while (!goodpos(nx
, ny
, worm
, 0) && (tryct
++ < 50));
638 place_worm_seg(worm
, nx
, ny
);
643 wtails
[wnum
]->nseg
= new_tail
;
644 new_tail
= wtails
[wnum
];
646 } else { /* Oops. Truncate because there was */
647 toss_wsegs(curr
, FALSE
); /* no place for the rest of it */
648 curr
= (struct wseg
*) 0;
654 * Given a coordinate x, y.
655 * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining.
657 * This function, and the loop it serves, could be eliminated by coding
658 * enexto() with a search radius.
662 random_dir(x
, y
, nx
, ny
)
664 register xchar
*nx
, *ny
;
669 *nx
+= (x
> 1 /* extreme left ? */
670 ? (x
< COLNO
/* extreme right ? */
671 ? (rn2(3) - 1) /* neither so +1, 0, or -1 */
672 : -rn2(2)) /* 0, or -1 */
673 : rn2(2)); /* 0, or 1 */
675 *ny
+= (*nx
== x
/* same kind of thing with y */
676 ? (y
> 1 ? (y
< ROWNO
? (rn2(2) ? 1 : -1) : -1) : 1)
677 : (y
> 1 ? (y
< ROWNO
? (rn2(3) - 1) : -rn2(2)) : rn2(2)));
680 /* for size_monst(cmd.c) to support #stats */
685 return (int) (count_wsegs(worm
) * sizeof (struct wseg
));
689 * returns the number of segments that a worm has.
696 register struct wseg
*curr
;
699 for (curr
= wtails
[mtmp
->wormno
]->nseg
; curr
; curr
= curr
->nseg
)
705 /* create_worm_tail()
706 * will create a worm tail chain of (num_segs + 1) and return pointer to it.
710 create_worm_tail(num_segs
)
714 register struct wseg
*new_tail
, *curr
;
717 return (struct wseg
*) 0;
719 new_tail
= curr
= newseg();
720 curr
->nseg
= (struct wseg
*) 0;
724 while (i
< num_segs
) {
725 curr
->nseg
= newseg();
727 curr
->nseg
= (struct wseg
*) 0;
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.
745 struct wseg
*curr
= wtails
[worm
->wormno
];
748 if (cansee(curr
->wx
, curr
->wy
))
755 /* would moving from <x1,y1> to <x2,y2> involve passing between two
756 consecutive segments of the same worm? */
758 worm_cross(x1
, y1
, x2
, y2
)
762 struct wseg
*curr
, *wnxt
;
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).
774 if (distmin(x1
, y1
, x2
, y2
) != 1) {
775 impossible("worm_cross checking for non-adjacent location?");
778 /* attempting to pass between worm segs is only relevant for diagonal */
779 if (x1
== x2
|| y1
== y2
)
782 /* is the same monster at <x1,y2> and at <x2,y1>? */
784 if (!worm
|| m_at(x2
, y1
) != worm
)
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
) {
792 break; /* no next segment; can't continue */
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
);
801 /* should never reach here... */
805 /* construct an index number for a worm tail segment */
813 if (worm
&& worm
->wormno
&& m_at(x
, y
) == worm
) {
816 xchar wx
= (xchar
) x
, wy
= (xchar
) y
;
818 for (i
= 0, curr
= wtails
[worm
->wormno
]; curr
; curr
= curr
->nseg
) {
819 if (curr
->wx
== wx
&& curr
->wy
== wy
)
823 for (n
= i
; curr
; curr
= curr
->nseg
)