xref: /dragonfly/games/hack/hack.worm.c (revision 92fc8b5c)
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 */
225