Blindfold removal fix
[slashemextended.git] / src / worm.c
blob8662f4f5ed5f410e169de22dc063817c4e95f5ee
1 /* SCCS Id: @(#)worm.c 3.4 1995/01/28 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include "lev.h"
8 #define newseg() (struct wseg *) alloc(sizeof(struct wseg))
9 #define dealloc_seg(wseg) free((void *) (wseg))
11 /* worm segment structure */
12 struct wseg {
13 struct wseg *nseg;
14 xchar wx, wy; /* the segment's position */
17 STATIC_DCL void toss_wsegs(struct wseg *,BOOLEAN_P);
18 STATIC_DCL void shrink_worm(int);
19 STATIC_DCL void random_dir(XCHAR_P,XCHAR_P,xchar *,xchar *);
20 STATIC_DCL struct wseg *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 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.
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;
73 * get_wormno()
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.
85 int
86 get_wormno()
88 register int new_wormno = 1;
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++;
96 return(0); /* level infested with worms */
100 * initworm()
102 * Use if (mon->wormno = get_wormno()) before calling this function!
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[].
107 * If the worm has no tail (ie get_wormno() fails) then this function need
108 * not be called.
110 void
111 initworm(worm, wseg_count)
112 struct monst *worm;
113 int wseg_count;
115 register struct wseg *seg, *new_tail = create_worm_tail(wseg_count);
116 register int wnum = worm->wormno;
118 /* if (!wnum) return; bullet proofing */
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;
130 wgrowtime[wnum] = 0L;
135 * toss_wsegs()
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.
140 STATIC_OVL
141 void
142 toss_wsegs(curr, display_update)
143 register struct wseg *curr;
144 register boolean display_update;
146 register struct wseg *seg;
148 while (curr) {
149 seg = curr->nseg;
151 /* remove from level.monsters[][] */
153 /* need to check curr->wx for genocided while migrating_mon */
154 if (curr->wx) {
155 remove_monster(curr->wx, curr->wy);
157 /* update screen before deallocation */
158 if (display_update) newsym(curr->wx,curr->wy);
161 /* free memory used by the segment */
162 dealloc_seg(curr);
163 curr = seg;
169 * shrink_worm()
171 * Remove the tail segment of the worm (the starting segment of the list).
173 STATIC_OVL
174 void
175 shrink_worm(wnum)
176 int wnum; /* worm number */
178 struct wseg *seg;
180 if (wtails[wnum] == wheads[wnum]) return; /* no tail */
182 seg = wtails[wnum];
183 wtails[wnum] = seg->nseg;
184 seg->nseg = (struct wseg *) 0;
185 toss_wsegs(seg, TRUE);
189 * worm_move()
191 * Check for mon->wormno before calling this function!
193 * Move the worm. Maybe grow.
195 void
196 worm_move(worm)
197 struct monst *worm;
199 register struct wseg *seg, *new_seg; /* new segment */
200 register int wnum = worm->wormno; /* worm number */
203 /* if (!wnum) return; bullet proofing */
206 * Place a segment at the old worm head. The head has already moved.
208 seg = wheads[wnum];
209 place_worm_seg(worm, seg->wx, seg->wy);
210 newsym(seg->wx,seg->wy); /* display the new segment */
213 * Create a new dummy segment head and place it at the end of the list.
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 */
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);
237 * worm_nomove()
239 * Check for mon->wormno before calling this function!
241 * The worm don't move so it should shrink.
243 void
244 worm_nomove(worm)
245 register struct monst *worm;
247 shrink_worm((int) worm->wormno); /* shrink */
249 if (worm->mhp > 3)
250 worm->mhp -= 3; /* mhpmax not changed ! */
251 else
252 worm->mhp = 1;
256 * wormgone()
258 * Check for mon->wormno before calling this function!
260 * Kill a worm tail.
262 void
263 wormgone(worm)
264 register struct monst *worm;
266 register int wnum = worm->wormno;
268 /* if (!wnum) return; bullet proofing */
270 worm->wormno = 0;
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;
281 * wormhitu()
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.
287 void
288 wormhitu(worm)
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 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.
301 for (seg = wtails[wnum]; seg; seg = seg->nseg)
302 if (distu(seg->wx, seg->wy) < 3)
303 (void) mattacku(worm);
306 /* cutworm()
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.
314 * [ALI] Return true if worm is cut.
317 cutworm(worm, x, y, weap)
318 struct monst *worm;
319 xchar x,y;
320 struct obj *weap;
322 register struct wseg *curr, *new_tail;
323 register struct monst *new_worm;
324 int wnum = worm->wormno;
325 int cut_chance, new_wnum;
327 if (!wnum) return 0; /* bullet proofing */
329 if (x == worm->mx && y == worm->my) return 0; /* 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 */
338 if (cut_chance < 17) return 0; /* not good enough */
340 /* Find the segment that was attacked. */
341 curr = wtails[wnum];
343 while ( (curr->wx != x) || (curr->wy != y) ) {
344 curr = curr->nseg;
345 if (!curr) {
346 impossible("cutworm: no segment at (%d,%d)", (int) x, (int) y);
347 return 0;
351 /* If this is the tail segment, then the worm just loses it. */
352 if (curr == wtails[wnum]) {
353 shrink_worm(wnum);
354 return 1;
358 * Split the worm. The tail for the new worm is the old worm's tail.
359 * The tail for the old worm is the segment that follows "curr",
360 * and "curr" becomes the dummy segment under the new head.
362 new_tail = wtails[wnum];
363 wtails[wnum] = curr->nseg;
364 curr->nseg = (struct wseg *) 0; /* split the worm */
367 * At this point, the old worm is correct. Any new worm will have
368 * it's head at "curr" and its tail at "new_tail".
371 /* Sometimes the tail end dies. */
372 if (rn2(3) || !(new_wnum = get_wormno())) {
373 if (flags.mon_moving)
374 pline("Part of the tail of %s is cut off.", mon_nam(worm));
375 else
376 You("cut part of the tail off of %s.", mon_nam(worm));
377 toss_wsegs(new_tail, TRUE);
378 if (worm->mhp > 1) worm->mhp /= 2;
379 return 1;
382 remove_monster(x, y); /* clone_mon puts new head here */
383 new_worm = clone_mon(worm, x, y);
384 if (!new_worm) { /* bugfix, I don't remember where I got it from --Amy */
385 return 0;
387 new_worm->wormno = new_wnum; /* affix new worm number */
389 /* Devalue the monster level of both halves of the worm. */
390 worm->m_lev = ((unsigned)worm->m_lev <= 3) ?
391 (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
392 new_worm->m_lev = worm->m_lev;
394 /* Calculate the mhp on the new_worm for the (lower) monster level. */
395 new_worm->mhpmax = new_worm->mhp = d((int)new_worm->m_lev, 8);
397 /* Calculate the mhp on the old worm for the (lower) monster level. */
398 if (worm->m_lev > 3) {
399 worm->mhpmax = d((int)worm->m_lev, 8);
400 if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
403 wtails[new_wnum] = new_tail; /* We've got all the info right now */
404 wheads[new_wnum] = curr; /* so we can do this faster than */
405 wgrowtime[new_wnum] = 0L; /* trying to call initworm(). */
407 /* Place the new monster at all the segment locations. */
408 place_wsegs(new_worm);
410 if (flags.mon_moving)
411 pline("%s is cut in half.", Monnam(worm));
412 else
413 You("cut %s in half.", mon_nam(worm));
415 return 1;
420 * see_wsegs()
422 * Refresh all of the segments of the given worm. This is only called
423 * from see_monster() in display.c or when a monster goes minvis. It
424 * is located here for modularity.
426 void
427 see_wsegs(worm)
428 struct monst *worm;
430 struct wseg *curr = wtails[worm->wormno];
432 /* if (!mtmp->wormno) return; bullet proofing */
434 while (curr != wheads[worm->wormno]) {
435 newsym(curr->wx,curr->wy);
436 curr = curr->nseg;
441 * detect_wsegs()
443 * Display all of the segments of the given worm for detection.
445 void
446 detect_wsegs(worm, use_detection_glyph)
447 struct monst *worm;
448 boolean use_detection_glyph;
450 int num;
451 struct wseg *curr = wtails[worm->wormno];
453 /* if (!mtmp->wormno) return; bullet proofing */
455 while (curr != wheads[worm->wormno]) {
456 num = use_detection_glyph ?
457 detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) :
458 monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
459 show_glyph(curr->wx,curr->wy,num);
460 curr = curr->nseg;
466 * save_worm()
468 * Save the worm information for later use. The count is the number
469 * of segments, including the dummy. Called from save.c.
471 void
472 save_worm(fd, mode)
473 int fd, mode;
475 int i;
476 int count;
477 struct wseg *curr, *temp;
479 if (perform_bwrite(mode)) {
480 for (i = 1; i < MAX_NUM_WORMS; i++) {
481 for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++;
482 /* Save number of segments */
483 bwrite(fd, (void *) &count, sizeof(int));
484 /* Save segment locations of the monster. */
485 if (count) {
486 for (curr = wtails[i]; curr; curr = curr->nseg) {
487 bwrite(fd, (void *) &(curr->wx), sizeof(xchar));
488 bwrite(fd, (void *) &(curr->wy), sizeof(xchar));
492 bwrite(fd, (void *) wgrowtime, sizeof(wgrowtime));
495 if (release_data(mode)) {
496 /* Free the segments only. savemonchn() will take care of the
497 * monsters. */
498 for (i = 1; i < MAX_NUM_WORMS; i++) {
499 if (!(curr = wtails[i])) continue;
501 while (curr) {
502 temp = curr->nseg;
503 dealloc_seg(curr); /* free the segment */
504 curr = temp;
506 wheads[i] = wtails[i] = (struct wseg *) 0;
513 * rest_worm()
515 * Restore the worm information from the save file. Called from restore.c
517 void
518 rest_worm(fd)
519 int fd;
521 int i, j, count;
522 struct wseg *curr, *temp;
524 for (i = 1; i < MAX_NUM_WORMS; i++) {
525 mread(fd, (void *) &count, sizeof(int));
526 if (!count) continue; /* none */
528 /* Get the segments. */
529 for (curr = (struct wseg *) 0, j = 0; j < count; j++) {
530 temp = newseg();
531 temp->nseg = (struct wseg *) 0;
532 mread(fd, (void *) &(temp->wx), sizeof(xchar));
533 mread(fd, (void *) &(temp->wy), sizeof(xchar));
534 if (curr)
535 curr->nseg = temp;
536 else
537 wtails[i] = temp;
538 curr = temp;
540 wheads[i] = curr;
542 mread(fd, (void *) wgrowtime, sizeof(wgrowtime));
546 * place_wsegs()
548 * Place the segments of the given worm. Called from restore.c
550 void
551 place_wsegs(worm)
552 struct monst *worm;
554 struct wseg *curr = wtails[worm->wormno];
556 /* if (!mtmp->wormno) return; bullet proofing */
558 while (curr != wheads[worm->wormno]) {
559 place_worm_seg(worm,curr->wx,curr->wy);
560 curr = curr->nseg;
565 * remove_worm()
567 * This function is equivalent to the remove_monster #define in
568 * rm.h, only it will take the worm *and* tail out of the levels array.
569 * It does not get rid of (dealloc) the worm tail structures, and it does
570 * not remove the mon from the fmon chain.
572 void
573 remove_worm(worm)
574 register struct monst *worm;
576 register struct wseg *curr = wtails[worm->wormno];
578 /* if (!mtmp->wormno) return; bullet proofing */
580 while (curr) {
581 remove_monster(curr->wx, curr->wy);
582 newsym(curr->wx, curr->wy);
583 curr = curr->nseg;
588 * place_worm_tail_randomly()
590 * Place a worm tail somewhere on a level behind the head.
591 * This routine essentially reverses the order of the wsegs from head
592 * to tail while placing them.
593 * x, and y are most likely the worm->mx, and worm->my, but don't *need* to
594 * be, if somehow the head is disjoint from the tail.
596 void
597 place_worm_tail_randomly(worm, x, y)
598 struct monst *worm;
599 xchar x, y;
601 int wnum = worm->wormno;
602 struct wseg *curr = wtails[wnum];
603 struct wseg *new_tail;
604 register xchar ox = x, oy = y;
606 /* if (!wnum) return; bullet proofing */
608 if (wnum && (!wtails[wnum] || !wheads[wnum]) ) {
609 impossible("place_worm_tail_randomly: wormno is set without a tail!");
610 return;
613 wheads[wnum] = new_tail = curr;
614 curr = curr->nseg;
615 new_tail->nseg = (struct wseg *) 0;
616 new_tail->wx = x;
617 new_tail->wy = y;
619 while(curr) {
620 xchar nx, ny;
621 char tryct = 0;
623 /* pick a random direction from x, y and search for goodpos() */
625 do {
626 random_dir(ox, oy, &nx, &ny);
627 } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50));
629 if (tryct < 50) {
630 place_worm_seg(worm, nx, ny);
631 curr->wx = ox = nx;
632 curr->wy = oy = ny;
633 wtails[wnum] = curr;
634 curr = curr->nseg;
635 wtails[wnum]->nseg = new_tail;
636 new_tail = wtails[wnum];
637 newsym(nx, ny);
638 } else { /* Oops. Truncate because there was */
639 toss_wsegs(curr, FALSE); /* no place for the rest of it */
640 curr = (struct wseg *) 0;
646 * Given a coordinate x, y.
647 * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining.
649 * This function, and the loop it serves, could be eliminated by coding
650 * enexto() with a search radius.
652 STATIC_OVL
653 void
654 random_dir(x, y, nx, ny)
655 register xchar x, y;
656 register xchar *nx, *ny;
658 *nx = x;
659 *ny = y;
661 *nx += (x > 1 ? /* extreme left ? */
662 (x < COLNO ? /* extreme right ? */
663 (rn2(3) - 1) /* neither so +1, 0, or -1 */
664 : -rn2(2)) /* 0, or -1 */
665 : rn2(2)); /* 0, or 1 */
667 *ny += (*nx == x ? /* same kind of thing with y */
668 (y > 1 ?
669 (y < ROWNO ?
670 (rn2(2) ?
672 : -1)
673 : -1)
674 : 1)
675 : (y > 1 ?
676 (y < ROWNO ?
677 (rn2(3) - 1)
678 : -rn2(2))
679 : rn2(2)));
682 /* count_wsegs()
684 * returns
685 * the number of visible segments that a worm has.
689 count_wsegs(mtmp)
690 struct monst *mtmp;
692 register int i=0;
693 register struct wseg *curr = (wtails[mtmp->wormno])->nseg;
695 /* if (!mtmp->wormno) return 0; bullet proofing */
697 while (curr) {
698 i++;
699 curr = curr->nseg;
702 return i;
705 /* create_worm_tail()
707 * will create a worm tail chain of (num_segs + 1) and return a pointer to it.
709 STATIC_OVL
710 struct wseg *
711 create_worm_tail(num_segs)
712 int num_segs;
714 register int i=0;
715 register struct wseg *new_tail, *curr;
717 if (!num_segs) return (struct wseg *)0;
719 new_tail = curr = newseg();
720 curr->nseg = (struct wseg *)0;
721 curr->wx = 0;
722 curr->wy = 0;
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++;
733 return (new_tail);
736 /* worm_known()
738 * Is any segment of this worm in viewing range? Note: caller must check
739 * invisibility and telepathy (which should only show the head anyway).
740 * Mostly used in the canseemon() macro.
742 boolean
743 worm_known(worm)
744 struct monst *worm;
746 struct wseg *curr = wtails[worm->wormno];
748 while (curr) {
749 if(cansee(curr->wx,curr->wy)) return TRUE;
750 curr = curr->nseg;
752 return FALSE;
755 /*worm.c*/