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