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