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