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