OSDN Git Service

no E-word
[nethackexpress/trunk.git] / src / worm.c
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. */
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("cutworm: 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         if (flags.mon_moving)
372             pline("Part of the tail of %s is cut off.", mon_nam(worm));
373         else
374             You("cut part of the tail off of %s.", mon_nam(worm));
375         toss_wsegs(new_tail, TRUE);
376         if (worm->mhp > 1) worm->mhp /= 2;
377         return;
378     }
379
380     remove_monster(x, y);               /* clone_mon puts new head here */
381     new_worm = clone_mon(worm, x, y);
382     new_worm->wormno = new_wnum;        /* affix new worm number */
383
384     /* Devalue the monster level of both halves of the worm. */
385     worm->m_lev = ((unsigned)worm->m_lev <= 3) ?
386                    (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
387     new_worm->m_lev = worm->m_lev;
388
389     /* Calculate the mhp on the new_worm for the (lower) monster level. */
390     new_worm->mhpmax = new_worm->mhp = d((int)new_worm->m_lev, 8);
391
392     /* Calculate the mhp on the old worm for the (lower) monster level. */
393     if (worm->m_lev > 3) {
394         worm->mhpmax = d((int)worm->m_lev, 8);
395         if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
396     }
397
398     wtails[new_wnum] = new_tail;        /* We've got all the info right now */
399     wheads[new_wnum] = curr;            /* so we can do this faster than    */
400     wgrowtime[new_wnum] = 0L;           /* trying to call initworm().       */
401
402     /* Place the new monster at all the segment locations. */
403     place_wsegs(new_worm);
404
405     if (flags.mon_moving)
406         pline("%s is cut in half.", Monnam(worm));
407     else
408         You("cut %s in half.", mon_nam(worm));
409 }
410
411
412 /*
413  *  see_wsegs()
414  *
415  *  Refresh all of the segments of the given worm.  This is only called
416  *  from see_monster() in display.c or when a monster goes minvis.  It
417  *  is located here for modularity.
418  */
419 void
420 see_wsegs(worm)
421     struct monst *worm;
422 {
423     struct wseg *curr = wtails[worm->wormno];
424
425 /*  if (!mtmp->wormno) return;  bullet proofing */
426
427     while (curr != wheads[worm->wormno]) {
428         newsym(curr->wx,curr->wy);
429         curr = curr->nseg;
430     }
431 }
432
433 /*
434  *  detect_wsegs()
435  *
436  *  Display all of the segments of the given worm for detection.
437  */
438 void
439 detect_wsegs(worm, use_detection_glyph)
440     struct monst *worm;
441     boolean use_detection_glyph;
442 {
443     int num;
444     struct wseg *curr = wtails[worm->wormno];
445
446 /*  if (!mtmp->wormno) return;  bullet proofing */
447
448     while (curr != wheads[worm->wormno]) {
449         num = use_detection_glyph ?
450                 detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) :
451                 monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
452         show_glyph(curr->wx,curr->wy,num);
453         curr = curr->nseg;
454     }
455 }
456
457
458 /*
459  *  save_worm()
460  *
461  *  Save the worm information for later use.  The count is the number
462  *  of segments, including the dummy.  Called from save.c.
463  */
464 void
465 save_worm(fd, mode)
466     int fd, mode;
467 {
468     int i;
469     int count;
470     struct wseg *curr, *temp;
471
472     if (perform_bwrite(mode)) {
473         for (i = 1; i < MAX_NUM_WORMS; i++) {
474             for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++;
475             /* Save number of segments */
476             bwrite(fd, (genericptr_t) &count, sizeof(int));
477             /* Save segment locations of the monster. */
478             if (count) {
479                 for (curr = wtails[i]; curr; curr = curr->nseg) {
480                     bwrite(fd, (genericptr_t) &(curr->wx), sizeof(xchar));
481                     bwrite(fd, (genericptr_t) &(curr->wy), sizeof(xchar));
482                 }
483             }
484         }
485         bwrite(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
486     }
487
488     if (release_data(mode)) {
489         /* Free the segments only.  savemonchn() will take care of the
490          * monsters. */
491         for (i = 1; i < MAX_NUM_WORMS; i++) {
492             if (!(curr = wtails[i])) continue;
493
494             while (curr) {
495                 temp = curr->nseg;
496                 dealloc_seg(curr);              /* free the segment */
497                 curr = temp;
498             }
499             wheads[i] = wtails[i] = (struct wseg *) 0;
500         }
501     }
502
503 }
504
505 /*
506  *  rest_worm()
507  *
508  *  Restore the worm information from the save file.  Called from restore.c
509  */
510 void
511 rest_worm(fd)
512     int fd;
513 {
514     int i, j, count;
515     struct wseg *curr, *temp;
516
517     for (i = 1; i < MAX_NUM_WORMS; i++) {
518         mread(fd, (genericptr_t) &count, sizeof(int));
519         if (!count) continue;   /* none */
520
521         /* Get the segments. */
522         for (curr = (struct wseg *) 0, j = 0; j < count; j++) {
523             temp = newseg();
524             temp->nseg = (struct wseg *) 0;
525             mread(fd, (genericptr_t) &(temp->wx), sizeof(xchar));
526             mread(fd, (genericptr_t) &(temp->wy), sizeof(xchar));
527             if (curr)
528                 curr->nseg = temp;
529             else
530                 wtails[i] = temp;
531             curr = temp;
532         }
533         wheads[i] = curr;
534     }
535     mread(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
536 }
537
538 /*
539  *  place_wsegs()
540  *
541  *  Place the segments of the given worm.  Called from restore.c
542  */
543 void
544 place_wsegs(worm)
545     struct monst *worm;
546 {
547     struct wseg *curr = wtails[worm->wormno];
548
549 /*  if (!mtmp->wormno) return;  bullet proofing */
550
551     while (curr != wheads[worm->wormno]) {
552         place_worm_seg(worm,curr->wx,curr->wy);
553         curr = curr->nseg;
554     }
555 }
556
557 /*
558  *  remove_worm()
559  *
560  *  This function is equivalent to the remove_monster #define in
561  *  rm.h, only it will take the worm *and* tail out of the levels array.
562  *  It does not get rid of (dealloc) the worm tail structures, and it does
563  *  not remove the mon from the fmon chain.
564  */
565 void
566 remove_worm(worm)
567     register struct monst *worm;
568 {
569     register struct wseg *curr = wtails[worm->wormno];
570
571 /*  if (!mtmp->wormno) return;  bullet proofing */
572
573     while (curr) {
574         remove_monster(curr->wx, curr->wy);
575         newsym(curr->wx, curr->wy);
576         curr = curr->nseg;
577     }
578 }
579
580 /*
581  *  place_worm_tail_randomly()
582  *
583  *  Place a worm tail somewhere on a level behind the head.
584  *  This routine essentially reverses the order of the wsegs from head
585  *  to tail while placing them.
586  *  x, and y are most likely the worm->mx, and worm->my, but don't *need* to
587  *  be, if somehow the head is disjoint from the tail.
588  */
589 void
590 place_worm_tail_randomly(worm, x, y)
591     struct monst *worm;
592     xchar x, y;
593 {
594     int wnum = worm->wormno;
595     struct wseg *curr = wtails[wnum];
596     struct wseg *new_tail;
597     register xchar ox = x, oy = y;
598
599 /*  if (!wnum) return;  bullet proofing */
600
601     if (wnum && (!wtails[wnum] || !wheads[wnum]) ) {
602         impossible("place_worm_tail_randomly: wormno is set without a tail!");
603         return;
604     }
605
606     wheads[wnum] = new_tail = curr;
607     curr = curr->nseg;
608     new_tail->nseg = (struct wseg *) 0;
609     new_tail->wx = x;
610     new_tail->wy = y;
611
612     while(curr)  {
613         xchar nx, ny;
614         char tryct = 0;
615
616         /* pick a random direction from x, y and search for goodpos() */
617
618         do {
619             random_dir(ox, oy, &nx, &ny);
620         } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50));
621
622         if (tryct < 50)  {
623             place_worm_seg(worm, nx, ny);
624             curr->wx = ox = nx;
625             curr->wy = oy = ny;
626             wtails[wnum] = curr;
627             curr = curr->nseg;
628             wtails[wnum]->nseg = new_tail;
629             new_tail = wtails[wnum];
630             newsym(nx, ny);
631         } else {                        /* Oops.  Truncate because there was */
632             toss_wsegs(curr, FALSE);    /* no place for the rest of it */
633             curr = (struct wseg *) 0;
634         }
635     }
636 }
637
638 /*
639  * Given a coordinate x, y.
640  * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining.
641  *
642  * This function, and the loop it serves, could be eliminated by coding
643  * enexto() with a search radius.
644  */
645 STATIC_OVL
646 void
647 random_dir(x, y, nx, ny)
648     register xchar   x,   y;
649     register xchar *nx, *ny;
650 {
651     *nx = x;
652     *ny = y;
653
654     *nx += (x > 1 ?                     /* extreme left ? */
655                 (x < COLNO ?             /* extreme right ? */
656                         (rn2(3) - 1)      /* neither so +1, 0, or -1 */
657                 :       -rn2(2))         /* 0, or -1 */
658            :    rn2(2));                /* 0, or 1 */
659
660     *ny += (*nx == x ?                  /* same kind of thing with y */
661                 (y > 1 ?
662                     (y < ROWNO ?
663                         (rn2(2) ?
664                             1
665                         :   -1)
666                     :   -1)
667                 :   1)
668             :   (y > 1 ?
669                     (y < ROWNO ?
670                         (rn2(3) - 1)
671                     :   -rn2(2))
672                 :   rn2(2)));
673 }
674
675 /*  count_wsegs()
676  *
677  *  returns
678  *  the number of visible segments that a worm has.
679  */
680
681 int
682 count_wsegs(mtmp)
683     struct monst *mtmp;
684 {
685     register int i=0;
686     register struct wseg *curr = (wtails[mtmp->wormno])->nseg;
687
688 /*  if (!mtmp->wormno) return 0;  bullet proofing */
689
690     while (curr) {
691         i++;
692         curr = curr->nseg;
693     }
694
695     return i;
696 }
697
698 /*  create_worm_tail()
699  *
700  *  will create a worm tail chain of (num_segs + 1) and return a pointer to it.
701  */
702 STATIC_OVL
703 struct wseg *
704 create_worm_tail(num_segs)
705     int num_segs;
706 {
707     register int i=0;
708     register struct wseg *new_tail, *curr;
709
710     if (!num_segs) return (struct wseg *)0;
711
712     new_tail = curr = newseg();
713     curr->nseg = (struct wseg *)0;
714     curr->wx = 0;
715     curr->wy = 0;
716
717     while (i < num_segs) {
718         curr->nseg = newseg();
719         curr = curr->nseg;
720         curr->nseg = (struct wseg *)0;
721         curr->wx = 0;
722         curr->wy = 0;
723         i++;
724     }
725
726     return (new_tail);
727 }
728
729 /*  worm_known()
730  *
731  *  Is any segment of this worm in viewing range?  Note: caller must check
732  *  invisibility and telepathy (which should only show the head anyway).
733  *  Mostly used in the canseemon() macro.
734  */
735 boolean
736 worm_known(worm)
737 struct monst *worm;
738 {
739     struct wseg *curr = wtails[worm->wormno];
740
741     while (curr) {
742         if(cansee(curr->wx,curr->wy)) return TRUE;
743         curr = curr->nseg;
744     }
745     return FALSE;
746 }
747
748 /*worm.c*/