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