1/*	$NetBSD: hack.potion.c,v 1.8 2009/08/12 07:28:41 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.potion.c,v 1.8 2009/08/12 07:28:41 dholland Exp $");
67#endif				/* not lint */
68
69#include "hack.h"
70#include "extern.h"
71
72static void ghost_from_bottle(void);
73
74int
75dodrink(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	}
262use_it:
263	useup(otmp);
264	return (1);
265}
266
267void
268pluslvl(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
283void
284strange_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
295static const char *const bottlenames[] = {
296	"bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
297};
298
299void
300potionhit(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
367void
368potionbreathe(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 */
429int
430dodip(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
450static void
451ghost_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