xref: /openbsd-src/games/hack/hack.mhitu.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: hack.mhitu.c,v 1.7 2009/10/27 23:59:25 deraadt 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	"hack.h"
65 extern struct monst *makemon();
66 
67 /*
68  * mhitu: monster hits you
69  *	  returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise
70  */
71 int
72 mhitu(struct monst *mtmp)
73 {
74 	struct permonst *mdat = mtmp->data;
75 	int tmp, ctmp;
76 
77 	nomul(0);
78 
79 	/* If swallowed, can only be affected by hissers and by u.ustuck */
80 	if(u.uswallow) {
81 		if(mtmp != u.ustuck) {
82 			if(mdat->mlet == 'c' && !rn2(13)) {
83 				pline("Outside, you hear %s's hissing!",
84 					monnam(mtmp));
85 				pline("%s gets turned to stone!",
86 					Monnam(u.ustuck));
87 				pline("And the same fate befalls you.");
88 				done_in_by(mtmp);
89 				/* "notreached": not return(1); */
90 			}
91 			return(0);
92 		}
93 		switch(mdat->mlet) {	/* now mtmp == u.ustuck */
94 		case ',':
95 			youswld(mtmp, (u.uac > 0) ? u.uac+4 : 4,
96 				5, "The trapper");
97 			break;
98 		case '\'':
99 			youswld(mtmp,rnd(6),7,"The lurker above");
100 			break;
101 		case 'P':
102 			youswld(mtmp,d(2,4),12,"The purple worm");
103 			break;
104 		default:
105 			/* This is not impossible! */
106 			pline("The mysterious monster totally digests you.");
107 			u.uhp = 0;
108 		}
109 		if(u.uhp < 1) done_in_by(mtmp);
110 		return(0);
111 	}
112 
113 	if(mdat->mlet == 'c' && Stoned)
114 		return(0);
115 
116 	/* make eels visible the moment they hit/miss us */
117 	if(mdat->mlet == ';' && mtmp->minvis && cansee(mtmp->mx,mtmp->my)){
118 		mtmp->minvis = 0;
119 		pmon(mtmp);
120 	}
121 	if(!strchr("1&DuxynNF",mdat->mlet))
122 		tmp = hitu(mtmp,d(mdat->damn,mdat->damd));
123 	else
124 		tmp = 0;
125 	if(strchr(UNDEAD, mdat->mlet) && midnight())
126 		tmp += hitu(mtmp,d(mdat->damn,mdat->damd));
127 
128 	ctmp = tmp && !mtmp->mcan &&
129 	  (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50));
130 	switch(mdat->mlet) {
131 	case '1':
132 		if(wiz_hit(mtmp)) return(1);	/* he disappeared */
133 		break;
134 	case '&':
135 		if(!mtmp->cham && !mtmp->mcan && !rn2(13)) {
136 			(void) makemon(PM_DEMON,u.ux,u.uy);
137 		} else {
138 			(void) hitu(mtmp,d(2,6));
139 			(void) hitu(mtmp,d(2,6));
140 			(void) hitu(mtmp,rnd(3));
141 			(void) hitu(mtmp,rnd(3));
142 			(void) hitu(mtmp,rn1(4,2));
143 		}
144 		break;
145 	case ',':
146 		if(tmp) justswld(mtmp,"The trapper");
147 		break;
148 	case '\'':
149 		if(tmp) justswld(mtmp, "The lurker above");
150 		break;
151 	case ';':
152 		if(ctmp) {
153 			if(!u.ustuck && !rn2(10)) {
154 				pline("%s swings itself around you!",
155 					Monnam(mtmp));
156 				u.ustuck = mtmp;
157 			} else if(u.ustuck == mtmp &&
158 			    levl[(int)mtmp->mx][(int)mtmp->my].typ == POOL) {
159 				pline("%s drowns you ...", Monnam(mtmp));
160 				done("drowned");
161 			}
162 		}
163 		break;
164 	case 'A':
165 		if(ctmp && rn2(2)) {
166 		    if(Poison_resistance)
167 			pline("The sting doesn't seem to affect you.");
168 		    else {
169 			pline("You feel weaker!");
170 			losestr(1);
171 		    }
172 		}
173 		break;
174 	case 'C':
175 		(void) hitu(mtmp,rnd(6));
176 		break;
177 	case 'c':
178 		if(!rn2(5)) {
179 			pline("You hear %s's hissing!", monnam(mtmp));
180 			if(ctmp || !rn2(20) || (flags.moonphase == NEW_MOON
181 			    && !carrying(DEAD_LIZARD))) {
182 				Stoned = 5;
183 				/* pline("You get turned to stone!"); */
184 				/* done_in_by(mtmp); */
185 			}
186 		}
187 		break;
188 	case 'D':
189 		if(rn2(6) || mtmp->mcan) {
190 			(void) hitu(mtmp,d(3,10));
191 			(void) hitu(mtmp,rnd(8));
192 			(void) hitu(mtmp,rnd(8));
193 			break;
194 		}
195 		kludge("%s breathes fire!","The dragon");
196 		buzz(-1,mtmp->mx,mtmp->my,u.ux-mtmp->mx,u.uy-mtmp->my);
197 		break;
198 	case 'd':
199 		(void) hitu(mtmp,d(2, (flags.moonphase == FULL_MOON) ? 3 : 4));
200 		break;
201 	case 'e':
202 		(void) hitu(mtmp,d(3,6));
203 		break;
204 	case 'F':
205 		if(mtmp->mcan) break;
206 		kludge("%s explodes!","The freezing sphere");
207 		if(Cold_resistance) pline("You don't seem affected by it.");
208 		else {
209 			xchar dn;
210 			if(17-(u.ulevel/2) > rnd(20)) {
211 				pline("You get blasted!");
212 				dn = 6;
213 			} else {
214 				pline("You duck the blast...");
215 				dn = 3;
216 			}
217 			losehp_m(d(dn,6), mtmp);
218 		}
219 		mondead(mtmp);
220 		return(1);
221 	case 'g':
222 		if(ctmp && multi >= 0 && !rn2(3)) {
223 			kludge("You are frozen by %ss juices","the cube'");
224 			nomul(-rnd(10));
225 		}
226 		break;
227 	case 'h':
228 		if(ctmp && multi >= 0 && !rn2(5)) {
229 			nomul(-rnd(10));
230 			kludge("You are put to sleep by %ss bite!",
231 				"the homunculus'");
232 		}
233 		break;
234 	case 'j':
235 		tmp = hitu(mtmp,rnd(3));
236 		tmp &= hitu(mtmp,rnd(3));
237 		if(tmp){
238 			(void) hitu(mtmp,rnd(4));
239 			(void) hitu(mtmp,rnd(4));
240 		}
241 		break;
242 	case 'k':
243 		if((hitu(mtmp,rnd(4)) || !rn2(3)) && ctmp){
244 			poisoned("bee's sting",mdat->mname);
245 		}
246 		break;
247 	case 'L':
248 		if(tmp) stealgold(mtmp);
249 		break;
250 	case 'N':
251 		if(mtmp->mcan && !Blind) {
252 	pline("%s tries to seduce you, but you seem not interested.",
253 			Amonnam(mtmp, "plain"));
254 			if(rn2(3)) rloc(mtmp);
255 		} else if(steal(mtmp)) {
256 			rloc(mtmp);
257 			mtmp->mflee = 1;
258 		}
259 		break;
260 	case 'n':
261 		if(!uwep && !uarm && !uarmh && !uarms && !uarmg) {
262 		    pline("%s hits! (I hope you don't mind)",
263 			Monnam(mtmp));
264 			u.uhp += rnd(7);
265 			if(!rn2(7)) u.uhpmax++;
266 			if(u.uhp > u.uhpmax) u.uhp = u.uhpmax;
267 			flags.botl = 1;
268 			if(!rn2(50)) rloc(mtmp);
269 		} else {
270 			(void) hitu(mtmp,d(2,6));
271 			(void) hitu(mtmp,d(2,6));
272 		}
273 		break;
274 	case 'o':
275 		tmp = hitu(mtmp,rnd(6));
276 		if(hitu(mtmp,rnd(6)) && tmp &&	/* hits with both paws */
277 		    !u.ustuck && rn2(2)) {
278 			u.ustuck = mtmp;
279 			kludge("%s has grabbed you!","The owlbear");
280 			u.uhp -= d(2,8);
281 		} else if(u.ustuck == mtmp) {
282 			u.uhp -= d(2,8);
283 			pline("You are being crushed.");
284 		}
285 		break;
286 	case 'P':
287 		if(ctmp && !rn2(4))
288 			justswld(mtmp,"The purple worm");
289 		else
290 			(void) hitu(mtmp,d(2,4));
291 		break;
292 	case 'Q':
293 		(void) hitu(mtmp,rnd(2));
294 		(void) hitu(mtmp,rnd(2));
295 		break;
296 	case 'R':
297 		if(tmp && uarmh && !uarmh->rustfree &&
298 		    (int) uarmh->spe >= -1) {
299 			pline("Your helmet rusts!");
300 			uarmh->spe--;
301 		} else
302 		if(ctmp && uarm && !uarm->rustfree &&	/* Mike Newton */
303 		 uarm->otyp < STUDDED_LEATHER_ARMOR &&
304 		 (int) uarm->spe >= -1) {
305 			pline("Your armor rusts!");
306 			uarm->spe--;
307 		}
308 		break;
309 	case 'S':
310 		if(ctmp && !rn2(8)) {
311 			poisoned("snake's bite",mdat->mname);
312 		}
313 		break;
314 	case 's':
315 		if(tmp && !rn2(8)) {
316 			poisoned("scorpion's sting",mdat->mname);
317 		}
318 		(void) hitu(mtmp,rnd(8));
319 		(void) hitu(mtmp,rnd(8));
320 		break;
321 	case 'T':
322 		(void) hitu(mtmp,rnd(6));
323 		(void) hitu(mtmp,rnd(6));
324 		break;
325 	case 't':
326 		if(!rn2(5)) rloc(mtmp);
327 		break;
328 	case 'u':
329 		mtmp->mflee = 1;
330 		break;
331 	case 'U':
332 		(void) hitu(mtmp,d(3,4));
333 		(void) hitu(mtmp,d(3,4));
334 		break;
335 	case 'v':
336 		if(ctmp && !u.ustuck) u.ustuck = mtmp;
337 		break;
338 	case 'V':
339 		if(tmp) u.uhp -= 4;
340 		if(ctmp) losexp();
341 		break;
342 	case 'W':
343 		if(ctmp) losexp();
344 		break;
345 #ifndef NOWORM
346 	case 'w':
347 		if(tmp) wormhit(mtmp);
348 #endif /* NOWORM */
349 		break;
350 	case 'X':
351 		(void) hitu(mtmp,rnd(5));
352 		(void) hitu(mtmp,rnd(5));
353 		(void) hitu(mtmp,rnd(5));
354 		break;
355 	case 'x':
356 		{ long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
357 		  pline("%s pricks in your %s leg!",
358 			Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left");
359 		  set_wounded_legs(side, rnd(50));
360 		  losehp_m(2, mtmp);
361 		  break;
362 		}
363 	case 'y':
364 		if(mtmp->mcan) break;
365 		mondead(mtmp);
366 		if(!Blind) {
367 			pline("You are blinded by a blast of light!");
368 			Blind = d(4,12);
369 			seeoff(0);
370 		}
371 		return(1);
372 	case 'Y':
373 		(void) hitu(mtmp,rnd(6));
374 		break;
375 	}
376 	if(u.uhp < 1) done_in_by(mtmp);
377 	return(0);
378 }
379 
380 int
381 hitu(struct monst *mtmp, int dam)
382 {
383 	int tmp, res;
384 
385 	nomul(0);
386 	if(u.uswallow) return(0);
387 
388 	if(mtmp->mhide && mtmp->mundetected) {
389 		mtmp->mundetected = 0;
390 		if(!Blind) {
391 			struct obj *obj;
392 			if ((obj = o_at(mtmp->mx,mtmp->my)))
393 				pline("%s was hidden under %s!",
394 					Xmonnam(mtmp), doname(obj));
395 		}
396 	}
397 
398 	tmp = u.uac;
399 	/* give people with Ac = -10 at least some vulnerability */
400 	if(tmp < 0) {
401 		dam += tmp;		/* decrease damage */
402 		if(dam <= 0) dam = 1;
403 		tmp = -rn2(-tmp);
404 	}
405 	tmp += mtmp->data->mlevel;
406 	if(multi < 0) tmp += 4;
407 	if((Invis && mtmp->data->mlet != 'I') || !mtmp->mcansee) tmp -= 2;
408 	if(mtmp->mtrapped) tmp -= 2;
409 	if(tmp <= rnd(20)) {
410 		if(Blind) pline("It misses.");
411 		else pline("%s misses.",Monnam(mtmp));
412 		res = 0;
413 	} else {
414 		if(Blind) pline("It hits!");
415 		else pline("%s hits!",Monnam(mtmp));
416 		losehp_m(dam, mtmp);
417 		res = 1;
418 	}
419 	stop_occupation();
420 	return(res);
421 }
422