3b7c24989f0c9681aaaa1b449be310f6dfd32887
[dragonfly.git] / games / hack / hack.worm.c
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.worm.c - version 1.0.2 */
3 /* $FreeBSD: src/games/hack/hack.worm.c,v 1.4 1999/11/16 10:26:38 marcel Exp $ */
4 /* $DragonFly: src/games/hack/hack.worm.c,v 1.4 2006/08/21 19:45:32 pavalos Exp $ */
5
6 #include "hack.h"
7 #ifndef NOWORM
8
9 struct wseg *wsegs[32]; /* linked list, tail first */
10 struct wseg *wheads[32];
11 long wgrowtime[32];
12
13 static void remseg(struct wseg *);
14
15 bool
16 getwn(struct monst *mtmp)
17 {
18         int tmp;
19
20         for (tmp = 1; tmp < 32; tmp++)
21                 if (!wsegs[tmp]) {
22                         mtmp->wormno = tmp;
23                         return (1);
24                 }
25         return (0);             /* level infested with worms */
26 }
27
28 /* called to initialize a worm unless cut in half */
29 void
30 initworm(struct monst *mtmp)
31 {
32         struct wseg *wtmp;
33         int tmp = mtmp->wormno;
34
35         if (!tmp)
36                 return;
37         wheads[tmp] = wsegs[tmp] = wtmp = newseg();
38         wgrowtime[tmp] = 0;
39         wtmp->wx = mtmp->mx;
40         wtmp->wy = mtmp->my;
41         wtmp->nseg = 0;
42 }
43
44 void
45 worm_move(struct monst *mtmp)
46 {
47         struct wseg *wtmp, *whd;
48         int tmp = mtmp->wormno;
49
50         wtmp = newseg();
51         wtmp->wx = mtmp->mx;
52         wtmp->wy = mtmp->my;
53         wtmp->nseg = 0;
54         (whd = wheads[tmp])->nseg = wtmp;
55         wheads[tmp] = wtmp;
56         if (cansee(whd->wx, whd->wy)) {
57                 unpmon(mtmp);
58                 atl(whd->wx, whd->wy, '~');
59                 whd->wdispl = 1;
60         } else
61                 whd->wdispl = 0;
62         if (wgrowtime[tmp] <= moves) {
63                 if (!wgrowtime[tmp])
64                         wgrowtime[tmp] = moves + rnd(5);
65                 else
66                         wgrowtime[tmp] += 2 + rnd(15);
67                 mtmp->mhpmax += 3;
68                 mtmp->mhp += 3;
69                 return;
70         }
71         whd = wsegs[tmp];
72         wsegs[tmp] = whd->nseg;
73         remseg(whd);
74 }
75
76 void
77 worm_nomove(struct monst *mtmp)
78 {
79         int tmp;
80         struct wseg *wtmp;
81
82         tmp = mtmp->wormno;
83         wtmp = wsegs[tmp];
84         if (wtmp == wheads[tmp])
85                 return;
86         if (wtmp == 0 || wtmp->nseg == 0)
87                 panic("worm_nomove?");
88         wsegs[tmp] = wtmp->nseg;
89         remseg(wtmp);
90         mtmp->mhp -= 3;         /* mhpmax not changed ! */
91 }
92
93 void
94 wormdead(struct monst *mtmp)
95 {
96         int tmp = mtmp->wormno;
97         struct wseg *wtmp, *wtmp2;
98
99         if (!tmp)
100                 return;
101         mtmp->wormno = 0;
102         for (wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2) {
103                 wtmp2 = wtmp->nseg;
104                 remseg(wtmp);
105         }
106         wsegs[tmp] = 0;
107 }
108
109 void
110 wormhit(struct monst *mtmp)
111 {
112         int tmp = mtmp->wormno;
113         struct wseg *wtmp;
114
115         if (!tmp)       /* worm without tail */
116                 return;
117         for (wtmp = wsegs[tmp]; wtmp; wtmp = wtmp->nseg)
118                 hitu(mtmp, 1);
119 }
120
121 void
122 wormsee(unsigned int tmp)
123 {
124         struct wseg *wtmp = wsegs[tmp];
125
126         if (!wtmp)
127                 panic("wormsee: wtmp==0");
128         for (; wtmp->nseg; wtmp = wtmp->nseg)
129                 if (!cansee(wtmp->wx, wtmp->wy) && wtmp->wdispl) {
130                         newsym(wtmp->wx, wtmp->wy);
131                         wtmp->wdispl = 0;
132                 }
133 }
134
135 void
136 pwseg(struct wseg *wtmp)
137 {
138         if (!wtmp->wdispl) {
139                 atl(wtmp->wx, wtmp->wy, '~');
140                 wtmp->wdispl = 1;
141         }
142 }
143
144 /* weptyp: uwep->otyp or 0 */
145 void
146 cutworm(struct monst *mtmp, xchar x, xchar y, uchar weptyp)
147 {
148         struct wseg *wtmp, *wtmp2;
149         struct monst *mtmp2;
150         int tmp, tmp2;
151
152         if (mtmp->mx == x && mtmp->my == y)     /* hit headon */
153                 return;
154
155         /* cutting goes best with axe or sword */
156         tmp = rnd(20);
157         if (weptyp == LONG_SWORD || weptyp == TWO_HANDED_SWORD ||
158             weptyp == AXE)
159                 tmp += 5;
160         if (tmp < 12)
161                 return;
162
163         /* if tail then worm just loses a tail segment */
164         tmp = mtmp->wormno;
165         wtmp = wsegs[tmp];
166         if (wtmp->wx == x && wtmp->wy == y) {
167                 wsegs[tmp] = wtmp->nseg;
168                 remseg(wtmp);
169                 return;
170         }
171
172         /* cut the worm in two halves */
173         mtmp2 = newmonst(0);
174         *mtmp2 = *mtmp;
175         mtmp2->mxlth = mtmp2->mnamelth = 0;
176
177         /* sometimes the tail end dies */
178         if (rn2(3) || !getwn(mtmp2)) {
179                 monfree(mtmp2);
180                 tmp2 = 0;
181         } else {
182                 tmp2 = mtmp2->wormno;
183                 wsegs[tmp2] = wsegs[tmp];
184                 wgrowtime[tmp2] = 0;
185         }
186         do {
187                 if (wtmp->nseg->wx == x && wtmp->nseg->wy == y) {
188                         if (tmp2)
189                                 wheads[tmp2] = wtmp;
190                         wsegs[tmp] = wtmp->nseg->nseg;
191                         remseg(wtmp->nseg);
192                         wtmp->nseg = 0;
193                         if (tmp2) {
194                                 pline("You cut the worm in half.");
195                                 mtmp2->mhpmax = mtmp2->mhp =
196                                     d(mtmp2->data->mlevel, 8);
197                                 mtmp2->mx = wtmp->wx;
198                                 mtmp2->my = wtmp->wy;
199                                 mtmp2->nmon = fmon;
200                                 fmon = mtmp2;
201                                 pmon(mtmp2);
202                         } else {
203                                 pline("You cut off part of the worm's tail.");
204                                 remseg(wtmp);
205                         }
206                         mtmp->mhp /= 2;
207                         return;
208                 }
209                 wtmp2 = wtmp->nseg;
210                 if (!tmp2)
211                         remseg(wtmp);
212                 wtmp = wtmp2;
213         } while (wtmp->nseg);
214         panic("Cannot find worm segment");
215 }
216
217 static void
218 remseg(struct wseg *wtmp)
219 {
220         if (wtmp->wdispl)
221                 newsym(wtmp->wx, wtmp->wy);
222         free(wtmp);
223 }
224 #endif /* NOWORM */