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