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