1 /*        $NetBSD: hack.potion.c,v 1.9 2011/05/23 22:53:25 joerg 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.potion.c,v 1.9 2011/05/23 22:53:25 joerg Exp $");
67 #endif                                  /* not lint */
68 
69 #include "hack.h"
70 #include "extern.h"
71 
72 static void ghost_from_bottle(void);
73 
74 int
dodrink(void)75 dodrink(void)
76 {
77           struct obj     *otmp, *objs;
78           struct monst   *mtmp;
79           int             unkn = 0, nothing = 0;
80 
81           otmp = getobj("!", "drink");
82           if (!otmp)
83                     return (0);
84           if (!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) {
85                     ghost_from_bottle();
86                     goto use_it;
87           }
88           switch (otmp->otyp) {
89           case POT_RESTORE_STRENGTH:
90                     unkn++;
91                     pline("Wow!  This makes you feel great!");
92                     if (u.ustr < u.ustrmax) {
93                               u.ustr = u.ustrmax;
94                               flags.botl = 1;
95                     }
96                     break;
97           case POT_BOOZE:
98                     unkn++;
99                     pline("Ooph!  This tastes like liquid fire!");
100                     Confusion += d(3, 8);
101                     /* the whiskey makes us feel better */
102                     if (u.uhp < u.uhpmax)
103                               losehp(-1, "bottle of whiskey");
104                     if (!rn2(4)) {
105                               pline("You pass out.");
106                               multi = -rnd(15);
107                               nomovemsg = "You awake with a headache.";
108                     }
109                     break;
110           case POT_INVISIBILITY:
111                     if (Invis || See_invisible)
112                               nothing++;
113                     else {
114                               if (!Blind)
115                                         pline("Gee!  All of a sudden, you can't see yourself.");
116                               else
117                                         pline("You feel rather airy."), unkn++;
118                               newsym(u.ux, u.uy);
119                     }
120                     Invis += rn1(15, 31);
121                     break;
122           case POT_FRUIT_JUICE:
123                     pline("This tastes like fruit juice.");
124                     lesshungry(20);
125                     break;
126           case POT_HEALING:
127                     pline("You begin to feel better.");
128                     flags.botl = 1;
129                     u.uhp += rnd(10);
130                     if (u.uhp > u.uhpmax)
131                               u.uhp = ++u.uhpmax;
132                     if (Blind)
133                               Blind = 1;          /* see on next move */
134                     if (Sick)
135                               Sick = 0;
136                     break;
137           case POT_PARALYSIS:
138                     if (Levitation)
139                               pline("You are motionlessly suspended.");
140                     else
141                               pline("Your feet are frozen to the floor!");
142                     nomul(-(rn1(10, 25)));
143                     break;
144           case POT_MONSTER_DETECTION:
145                     if (!fmon) {
146                               strange_feeling(otmp, "You feel threatened.");
147                               return (1);
148                     } else {
149                               cls();
150                               for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
151                                         if (mtmp->mx > 0)
152                                                   at(mtmp->mx, mtmp->my, mtmp->data->mlet);
153                               prme();
154                               pline("You sense the presence of monsters.");
155                               more();
156                               docrt();
157                     }
158                     break;
159           case POT_OBJECT_DETECTION:
160                     if (!fobj) {
161                               strange_feeling(otmp, "You feel a pull downward.");
162                               return (1);
163                     } else {
164                               for (objs = fobj; objs; objs = objs->nobj)
165                                         if (objs->ox != u.ux || objs->oy != u.uy)
166                                                   goto outobjmap;
167                               pline("You sense the presence of objects close nearby.");
168                               break;
169           outobjmap:
170                               cls();
171                               for (objs = fobj; objs; objs = objs->nobj)
172                                         at(objs->ox, objs->oy, objs->olet);
173                               prme();
174                               pline("You sense the presence of objects.");
175                               more();
176                               docrt();
177                     }
178                     break;
179           case POT_SICKNESS:
180                     pline("Yech! This stuff tastes like poison.");
181                     if (Poison_resistance)
182                               pline("(But in fact it was biologically contaminated orange juice.)");
183                     losestr(rn1(4, 3));
184                     losehp(rnd(10), "contaminated potion");
185                     break;
186           case POT_CONFUSION:
187                     if (!Confusion)
188                               pline("Huh, What?  Where am I?");
189                     else
190                               nothing++;
191                     Confusion += rn1(7, 16);
192                     break;
193           case POT_GAIN_STRENGTH:
194                     pline("Wow do you feel strong!");
195                     if (u.ustr >= 118)
196                               break;    /* > 118 is impossible */
197                     if (u.ustr > 17)
198                               u.ustr += rnd(118 - u.ustr);
199                     else
200                               u.ustr++;
201                     if (u.ustr > u.ustrmax)
202                               u.ustrmax = u.ustr;
203                     flags.botl = 1;
204                     break;
205           case POT_SPEED:
206                     if (Wounded_legs) {
207                               heal_legs();
208                               unkn++;
209                               break;
210                     }
211                     if (!(Fast & ~INTRINSIC))
212                               pline("You are suddenly moving much faster.");
213                     else
214                               pline("Your legs get new energy."), unkn++;
215                     Fast += rn1(10, 100);
216                     break;
217           case POT_BLINDNESS:
218                     if (!Blind)
219                               pline("A cloud of darkness falls upon you.");
220                     else
221                               nothing++;
222                     Blind += rn1(100, 250);
223                     seeoff(0);
224                     break;
225           case POT_GAIN_LEVEL:
226                     pluslvl();
227                     break;
228           case POT_EXTRA_HEALING:
229                     pline("You feel much better.");
230                     flags.botl = 1;
231                     u.uhp += d(2, 20) + 1;
232                     if (u.uhp > u.uhpmax)
233                               u.uhp = (u.uhpmax += 2);
234                     if (Blind)
235                               Blind = 1;
236                     if (Sick)
237                               Sick = 0;
238                     break;
239           case POT_LEVITATION:
240                     if (!Levitation)
241                               float_up();
242                     else
243                               nothing++;
244                     Levitation += rnd(100);
245                     u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
246                     break;
247           default:
248                     impossible("What a funny potion! (%u)", otmp->otyp);
249                     return (0);
250           }
251           if (nothing) {
252                     unkn++;
253                     pline("You have a peculiar feeling for a moment, then it passes.");
254           }
255           if (otmp->dknown && !objects[otmp->otyp].oc_name_known) {
256                     if (!unkn) {
257                               objects[otmp->otyp].oc_name_known = 1;
258                               more_experienced(0, 10);
259                     } else if (!objects[otmp->otyp].oc_uname)
260                               docall(otmp);
261           }
262 use_it:
263           useup(otmp);
264           return (1);
265 }
266 
267 void
pluslvl(void)268 pluslvl(void)
269 {
270           int num;
271 
272           pline("You feel more experienced.");
273           num = rnd(10);
274           u.uhpmax += num;
275           u.uhp += num;
276           if (u.ulevel < 14) {
277                     u.uexp = newuexp() + 1;
278                     pline("Welcome to experience level %u.", ++u.ulevel);
279           }
280           flags.botl = 1;
281 }
282 
283 void
strange_feeling(struct obj * obj,const char * txt)284 strange_feeling(struct obj *obj, const char *txt)
285 {
286           if (flags.beginner)
287                     pline("You have a strange feeling for a moment, then it passes.");
288           else
289                     pline("%s", txt);
290           if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
291                     docall(obj);
292           useup(obj);
293 }
294 
295 static const char *const bottlenames[] = {
296           "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
297 };
298 
299 void
potionhit(struct monst * mon,struct obj * obj)300 potionhit(struct monst *mon, struct obj *obj)
301 {
302           const char           *botlnam = bottlenames[rn2(SIZE(bottlenames))];
303           boolean         uclose, isyou = (mon == &youmonst);
304 
305           if (isyou) {
306                     uclose = TRUE;
307                     pline("The %s crashes on your head and breaks into shivers.",
308                           botlnam);
309                     losehp(rnd(2), "thrown potion");
310           } else {
311                     uclose = (dist(mon->mx, mon->my) < 3);
312                     /* perhaps 'E' and 'a' have no head? */
313                     pline("The %s crashes on %s's head and breaks into shivers.",
314                           botlnam, monnam(mon));
315                     if (rn2(5) && mon->mhp > 1)
316                               mon->mhp--;
317           }
318           pline("The %s evaporates.", xname(obj));
319 
320           if (!isyou && !rn2(3))
321                     switch (obj->otyp) {
322 
323                     case POT_RESTORE_STRENGTH:
324                     case POT_GAIN_STRENGTH:
325                     case POT_HEALING:
326                     case POT_EXTRA_HEALING:
327                               if (mon->mhp < mon->mhpmax) {
328                                         mon->mhp = mon->mhpmax;
329                                         pline("%s looks sound and hale again!", Monnam(mon));
330                               }
331                               break;
332                     case POT_SICKNESS:
333                               if (mon->mhpmax > 3)
334                                         mon->mhpmax /= 2;
335                               if (mon->mhp > 2)
336                                         mon->mhp /= 2;
337                               break;
338                     case POT_CONFUSION:
339                     case POT_BOOZE:
340                               mon->mconf = 1;
341                               break;
342                     case POT_INVISIBILITY:
343                               unpmon(mon);
344                               mon->minvis = 1;
345                               pmon(mon);
346                               break;
347                     case POT_PARALYSIS:
348                               mon->mfroz = 1;
349                               break;
350                     case POT_SPEED:
351                               mon->mspeed = MFAST;
352                               break;
353                     case POT_BLINDNESS:
354                               mon->mblinded |= 64 + rn2(64);
355                               break;
356                               /*
357                                * case POT_GAIN_LEVEL: case POT_LEVITATION: case
358                                * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case
359                                * POT_OBJECT_DETECTION: break;
360                                */
361                     }
362           if (uclose && rn2(5))
363                     potionbreathe(obj);
364           obfree(obj, Null(obj));
365 }
366 
367 void
potionbreathe(struct obj * obj)368 potionbreathe(struct obj *obj)
369 {
370           switch (obj->otyp) {
371           case POT_RESTORE_STRENGTH:
372           case POT_GAIN_STRENGTH:
373                     if (u.ustr < u.ustrmax)
374                               u.ustr++, flags.botl = 1;
375                     break;
376           case POT_HEALING:
377           case POT_EXTRA_HEALING:
378                     if (u.uhp < u.uhpmax)
379                               u.uhp++, flags.botl = 1;
380                     break;
381           case POT_SICKNESS:
382                     if (u.uhp <= 5)
383                               u.uhp = 1;
384                     else
385                               u.uhp -= 5;
386                     flags.botl = 1;
387                     break;
388           case POT_CONFUSION:
389           case POT_BOOZE:
390                     if (!Confusion)
391                               pline("You feel somewhat dizzy.");
392                     Confusion += rnd(5);
393                     break;
394           case POT_INVISIBILITY:
395                     pline("For an instant you couldn't see your right hand.");
396                     break;
397           case POT_PARALYSIS:
398                     pline("Something seems to be holding you.");
399                     nomul(-rnd(5));
400                     break;
401           case POT_SPEED:
402                     Fast += rnd(5);
403                     pline("Your knees seem more flexible now.");
404                     break;
405           case POT_BLINDNESS:
406                     if (!Blind)
407                               pline("It suddenly gets dark.");
408                     Blind += rnd(5);
409                     seeoff(0);
410                     break;
411                     /*
412                      * case POT_GAIN_LEVEL: case POT_LEVITATION: case
413                      * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case
414                      * POT_OBJECT_DETECTION: break;
415                      */
416           }
417           /* note: no obfree() */
418 }
419 
420 /*
421  * -- rudimentary -- to do this correctly requires much more work
422  * -- all sharp weapons get one or more qualities derived from the potions
423  * -- texts on scrolls may be (partially) wiped out; do they become blank?
424  * --   or does their effect change, like under Confusion?
425  * -- all objects may be made invisible by POT_INVISIBILITY
426  * -- If the flask is small, can one dip a large object? Does it magically
427  * --   become a jug? Etc.
428  */
429 int
dodip(void)430 dodip(void)
431 {
432           struct obj     *potion, *obj;
433 
434           if (!(obj = getobj("#", "dip")))
435                     return (0);
436           if (!(potion = getobj("!", "dip into")))
437                     return (0);
438           pline("Interesting...");
439           if (obj->otyp == ARROW || obj->otyp == DART ||
440               obj->otyp == CROSSBOW_BOLT) {
441                     if (potion->otyp == POT_SICKNESS) {
442                               useup(potion);
443                               if (obj->spe < 7)
444                                         obj->spe++;         /* %% */
445                     }
446           }
447           return (1);
448 }
449 
450 static void
ghost_from_bottle(void)451 ghost_from_bottle(void)
452 {
453           struct monst   *mtmp;
454 
455           if (!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) {
456                     pline("This bottle turns out to be empty.");
457                     return;
458           }
459           mnexto(mtmp);
460           pline("As you open the bottle, an enormous ghost emerges!");
461           pline("You are frightened to death, and unable to move.");
462           nomul(-3);
463 }
464