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