xref: /netbsd-src/games/hack/hack.mhitu.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: hack.mhitu.c,v 1.6 2003/04/02 18:36:37 jsm Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.mhitu.c,v 1.6 2003/04/02 18:36:37 jsm Exp $");
67 #endif				/* not lint */
68 
69 #include "hack.h"
70 #include "extern.h"
71 
72 /*
73  * mhitu: monster hits you
74  *	  returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise
75  */
76 int
77 mhitu(mtmp)
78 	struct monst   *mtmp;
79 {
80 	const struct permonst *mdat = mtmp->data;
81 	int             tmp, ctmp;
82 
83 	nomul(0);
84 
85 	/* If swallowed, can only be affected by hissers and by u.ustuck */
86 	if (u.uswallow) {
87 		if (mtmp != u.ustuck) {
88 			if (mdat->mlet == 'c' && !rn2(13)) {
89 				pline("Outside, you hear %s's hissing!",
90 				      monnam(mtmp));
91 				pline("%s gets turned to stone!",
92 				      Monnam(u.ustuck));
93 				pline("And the same fate befalls you.");
94 				done_in_by(mtmp);
95 				/* "notreached": not return(1); */
96 			}
97 			return (0);
98 		}
99 		switch (mdat->mlet) {	/* now mtmp == u.ustuck */
100 		case ',':
101 			youswld(mtmp, (u.uac > 0) ? u.uac + 4 : 4,
102 				5, "The trapper");
103 			break;
104 		case '\'':
105 			youswld(mtmp, rnd(6), 7, "The lurker above");
106 			break;
107 		case 'P':
108 			youswld(mtmp, d(2, 4), 12, "The purple worm");
109 			break;
110 		default:
111 			/* This is not impossible! */
112 			pline("The mysterious monster totally digests you.");
113 			u.uhp = 0;
114 		}
115 		if (u.uhp < 1)
116 			done_in_by(mtmp);
117 		return (0);
118 	}
119 	if (mdat->mlet == 'c' && Stoned)
120 		return (0);
121 
122 	/* make eels visible the moment they hit/miss us */
123 	if (mdat->mlet == ';' && mtmp->minvis && cansee(mtmp->mx, mtmp->my)) {
124 		mtmp->minvis = 0;
125 		pmon(mtmp);
126 	}
127 	if (!strchr("1&DuxynNF", mdat->mlet))
128 		tmp = hitu(mtmp, d(mdat->damn, mdat->damd));
129 	else
130 		tmp = 0;
131 	if (strchr(UNDEAD, mdat->mlet) && midnight())
132 		tmp += hitu(mtmp, d(mdat->damn, mdat->damd));
133 
134 	ctmp = tmp && !mtmp->mcan &&
135 		(!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50));
136 	switch (mdat->mlet) {
137 	case '1':
138 		if (wiz_hit(mtmp))
139 			return (1);	/* he disappeared */
140 		break;
141 	case '&':
142 		if (!mtmp->cham && !mtmp->mcan && !rn2(13)) {
143 			(void) makemon(PM_DEMON, u.ux, u.uy);
144 		} else {
145 			(void) hitu(mtmp, d(2, 6));
146 			(void) hitu(mtmp, d(2, 6));
147 			(void) hitu(mtmp, rnd(3));
148 			(void) hitu(mtmp, rnd(3));
149 			(void) hitu(mtmp, rn1(4, 2));
150 		}
151 		break;
152 	case ',':
153 		if (tmp)
154 			justswld(mtmp, "The trapper");
155 		break;
156 	case '\'':
157 		if (tmp)
158 			justswld(mtmp, "The lurker above");
159 		break;
160 	case ';':
161 		if (ctmp) {
162 			if (!u.ustuck && !rn2(10)) {
163 				pline("%s swings itself around you!",
164 				      Monnam(mtmp));
165 				u.ustuck = mtmp;
166 			} else if (u.ustuck == mtmp &&
167 				   levl[mtmp->mx][mtmp->my].typ == POOL) {
168 				pline("%s drowns you ...", Monnam(mtmp));
169 				done("drowned");
170 			}
171 		}
172 		break;
173 	case 'A':
174 		if (ctmp && rn2(2)) {
175 			if (Poison_resistance)
176 				pline("The sting doesn't seem to affect you.");
177 			else {
178 				pline("You feel weaker!");
179 				losestr(1);
180 			}
181 		}
182 		break;
183 	case 'C':
184 		(void) hitu(mtmp, rnd(6));
185 		break;
186 	case 'c':
187 		if (!rn2(5)) {
188 			pline("You hear %s's hissing!", monnam(mtmp));
189 			if (ctmp || !rn2(20) || (flags.moonphase == NEW_MOON
190 					       && !carrying(DEAD_LIZARD))) {
191 				Stoned = 5;
192 				/* pline("You get turned to stone!"); */
193 				/* done_in_by(mtmp); */
194 			}
195 		}
196 		break;
197 	case 'D':
198 		if (rn2(6) || mtmp->mcan) {
199 			(void) hitu(mtmp, d(3, 10));
200 			(void) hitu(mtmp, rnd(8));
201 			(void) hitu(mtmp, rnd(8));
202 			break;
203 		}
204 		kludge("%s breathes fire!", "The dragon");
205 		buzz(-1, mtmp->mx, mtmp->my, u.ux - mtmp->mx, u.uy - mtmp->my);
206 		break;
207 	case 'd':
208 		(void) hitu(mtmp, d(2, (flags.moonphase == FULL_MOON) ? 3 : 4));
209 		break;
210 	case 'e':
211 		(void) hitu(mtmp, d(3, 6));
212 		break;
213 	case 'F':
214 		if (mtmp->mcan)
215 			break;
216 		kludge("%s explodes!", "The freezing sphere");
217 		if (Cold_resistance)
218 			pline("You don't seem affected by it.");
219 		else {
220 			xchar           dn;
221 			if (17 - (u.ulevel / 2) > rnd(20)) {
222 				pline("You get blasted!");
223 				dn = 6;
224 			} else {
225 				pline("You duck the blast...");
226 				dn = 3;
227 			}
228 			losehp_m(d(dn, 6), mtmp);
229 		}
230 		mondead(mtmp);
231 		return (1);
232 	case 'g':
233 		if (ctmp && multi >= 0 && !rn2(3)) {
234 			kludge("You are frozen by %ss juices", "the cube'");
235 			nomul(-rnd(10));
236 		}
237 		break;
238 	case 'h':
239 		if (ctmp && multi >= 0 && !rn2(5)) {
240 			nomul(-rnd(10));
241 			kludge("You are put to sleep by %ss bite!",
242 			       "the homunculus'");
243 		}
244 		break;
245 	case 'j':
246 		tmp = hitu(mtmp, rnd(3));
247 		tmp &= hitu(mtmp, rnd(3));
248 		if (tmp) {
249 			(void) hitu(mtmp, rnd(4));
250 			(void) hitu(mtmp, rnd(4));
251 		}
252 		break;
253 	case 'k':
254 		if ((hitu(mtmp, rnd(4)) || !rn2(3)) && ctmp) {
255 			poisoned("bee's sting", mdat->mname);
256 		}
257 		break;
258 	case 'L':
259 		if (tmp)
260 			stealgold(mtmp);
261 		break;
262 	case 'N':
263 		if (mtmp->mcan && !Blind) {
264 			pline("%s tries to seduce you, but you seem not interested.",
265 			      Amonnam(mtmp, "plain"));
266 			if (rn2(3))
267 				rloc(mtmp);
268 		} else if (steal(mtmp)) {
269 			rloc(mtmp);
270 			mtmp->mflee = 1;
271 		}
272 		break;
273 	case 'n':
274 		if (!uwep && !uarm && !uarmh && !uarms && !uarmg) {
275 			pline("%s hits! (I hope you don't mind)",
276 			      Monnam(mtmp));
277 			u.uhp += rnd(7);
278 			if (!rn2(7))
279 				u.uhpmax++;
280 			if (u.uhp > u.uhpmax)
281 				u.uhp = u.uhpmax;
282 			flags.botl = 1;
283 			if (!rn2(50))
284 				rloc(mtmp);
285 		} else {
286 			(void) hitu(mtmp, d(2, 6));
287 			(void) hitu(mtmp, d(2, 6));
288 		}
289 		break;
290 	case 'o':
291 		tmp = hitu(mtmp, rnd(6));
292 		if (hitu(mtmp, rnd(6)) && tmp &&	/* hits with both paws */
293 		    !u.ustuck && rn2(2)) {
294 			u.ustuck = mtmp;
295 			kludge("%s has grabbed you!", "The owlbear");
296 			u.uhp -= d(2, 8);
297 		} else if (u.ustuck == mtmp) {
298 			u.uhp -= d(2, 8);
299 			pline("You are being crushed.");
300 		}
301 		break;
302 	case 'P':
303 		if (ctmp && !rn2(4))
304 			justswld(mtmp, "The purple worm");
305 		else
306 			(void) hitu(mtmp, d(2, 4));
307 		break;
308 	case 'Q':
309 		(void) hitu(mtmp, rnd(2));
310 		(void) hitu(mtmp, rnd(2));
311 		break;
312 	case 'R':
313 		if (tmp && uarmh && !uarmh->rustfree &&
314 		    (int) uarmh->spe >= -1) {
315 			pline("Your helmet rusts!");
316 			uarmh->spe--;
317 		} else if (ctmp && uarm && !uarm->rustfree &&	/* Mike Newton */
318 			   uarm->otyp < STUDDED_LEATHER_ARMOR &&
319 			   (int) uarm->spe >= -1) {
320 			pline("Your armor rusts!");
321 			uarm->spe--;
322 		}
323 		break;
324 	case 'S':
325 		if (ctmp && !rn2(8)) {
326 			poisoned("snake's bite", mdat->mname);
327 		}
328 		break;
329 	case 's':
330 		if (tmp && !rn2(8)) {
331 			poisoned("scorpion's sting", mdat->mname);
332 		}
333 		(void) hitu(mtmp, rnd(8));
334 		(void) hitu(mtmp, rnd(8));
335 		break;
336 	case 'T':
337 		(void) hitu(mtmp, rnd(6));
338 		(void) hitu(mtmp, rnd(6));
339 		break;
340 	case 't':
341 		if (!rn2(5))
342 			rloc(mtmp);
343 		break;
344 	case 'u':
345 		mtmp->mflee = 1;
346 		break;
347 	case 'U':
348 		(void) hitu(mtmp, d(3, 4));
349 		(void) hitu(mtmp, d(3, 4));
350 		break;
351 	case 'v':
352 		if (ctmp && !u.ustuck)
353 			u.ustuck = mtmp;
354 		break;
355 	case 'V':
356 		if (tmp)
357 			u.uhp -= 4;
358 		if (ctmp)
359 			losexp();
360 		break;
361 	case 'W':
362 		if (ctmp)
363 			losexp();
364 		break;
365 #ifndef NOWORM
366 	case 'w':
367 		if (tmp)
368 			wormhit(mtmp);
369 #endif	/* NOWORM */
370 		break;
371 	case 'X':
372 		(void) hitu(mtmp, rnd(5));
373 		(void) hitu(mtmp, rnd(5));
374 		(void) hitu(mtmp, rnd(5));
375 		break;
376 	case 'x':
377 		{
378 			long            side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
379 			pline("%s pricks in your %s leg!",
380 			      Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left");
381 			set_wounded_legs(side, rnd(50));
382 			losehp_m(2, mtmp);
383 			break;
384 		}
385 	case 'y':
386 		if (mtmp->mcan)
387 			break;
388 		mondead(mtmp);
389 		if (!Blind) {
390 			pline("You are blinded by a blast of light!");
391 			Blind = d(4, 12);
392 			seeoff(0);
393 		}
394 		return (1);
395 	case 'Y':
396 		(void) hitu(mtmp, rnd(6));
397 		break;
398 	}
399 	if (u.uhp < 1)
400 		done_in_by(mtmp);
401 	return (0);
402 }
403 
404 int
405 hitu(mtmp, dam)
406 	struct monst   *mtmp;
407 	int dam;
408 {
409 	int tmp, res;
410 
411 	nomul(0);
412 	if (u.uswallow)
413 		return (0);
414 
415 	if (mtmp->mhide && mtmp->mundetected) {
416 		mtmp->mundetected = 0;
417 		if (!Blind) {
418 			struct obj     *obj;
419 			if ((obj = o_at(mtmp->mx, mtmp->my)) != NULL)
420 				pline("%s was hidden under %s!",
421 				      Xmonnam(mtmp), doname(obj));
422 		}
423 	}
424 	tmp = u.uac;
425 	/* give people with Ac = -10 at least some vulnerability */
426 	if (tmp < 0) {
427 		dam += tmp;	/* decrease damage */
428 		if (dam <= 0)
429 			dam = 1;
430 		tmp = -rn2(-tmp);
431 	}
432 	tmp += mtmp->data->mlevel;
433 	if (multi < 0)
434 		tmp += 4;
435 	if ((Invis && mtmp->data->mlet != 'I') || !mtmp->mcansee)
436 		tmp -= 2;
437 	if (mtmp->mtrapped)
438 		tmp -= 2;
439 	if (tmp <= rnd(20)) {
440 		if (Blind)
441 			pline("It misses.");
442 		else
443 			pline("%s misses.", Monnam(mtmp));
444 		res = 0;
445 	} else {
446 		if (Blind)
447 			pline("It hits!");
448 		else
449 			pline("%s hits!", Monnam(mtmp));
450 		losehp_m(dam, mtmp);
451 		res = 1;
452 	}
453 	stop_occupation();
454 	return (res);
455 }
456