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