hack.potion.c revision 1.8 1 1.8 dholland /* $NetBSD: hack.potion.c,v 1.8 2009/08/12 07:28:41 dholland Exp $ */
2 1.4 christos
3 1.2 mycroft /*
4 1.6 jsm * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5 1.6 jsm * Amsterdam
6 1.6 jsm * All rights reserved.
7 1.6 jsm *
8 1.6 jsm * Redistribution and use in source and binary forms, with or without
9 1.6 jsm * modification, are permitted provided that the following conditions are
10 1.6 jsm * met:
11 1.6 jsm *
12 1.6 jsm * - Redistributions of source code must retain the above copyright notice,
13 1.6 jsm * this list of conditions and the following disclaimer.
14 1.6 jsm *
15 1.6 jsm * - Redistributions in binary form must reproduce the above copyright
16 1.6 jsm * notice, this list of conditions and the following disclaimer in the
17 1.6 jsm * documentation and/or other materials provided with the distribution.
18 1.6 jsm *
19 1.6 jsm * - Neither the name of the Stichting Centrum voor Wiskunde en
20 1.6 jsm * Informatica, nor the names of its contributors may be used to endorse or
21 1.6 jsm * promote products derived from this software without specific prior
22 1.6 jsm * written permission.
23 1.6 jsm *
24 1.6 jsm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 1.6 jsm * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 1.6 jsm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 1.6 jsm * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28 1.6 jsm * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 1.6 jsm * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 1.6 jsm * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 1.6 jsm * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 1.6 jsm * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 1.6 jsm */
36 1.6 jsm
37 1.6 jsm /*
38 1.6 jsm * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org>
39 1.6 jsm * All rights reserved.
40 1.6 jsm *
41 1.6 jsm * Redistribution and use in source and binary forms, with or without
42 1.6 jsm * modification, are permitted provided that the following conditions
43 1.6 jsm * are met:
44 1.6 jsm * 1. Redistributions of source code must retain the above copyright
45 1.6 jsm * notice, this list of conditions and the following disclaimer.
46 1.6 jsm * 2. Redistributions in binary form must reproduce the above copyright
47 1.6 jsm * notice, this list of conditions and the following disclaimer in the
48 1.6 jsm * documentation and/or other materials provided with the distribution.
49 1.6 jsm * 3. The name of the author may not be used to endorse or promote products
50 1.6 jsm * derived from this software without specific prior written permission.
51 1.6 jsm *
52 1.6 jsm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53 1.6 jsm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 1.6 jsm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
55 1.6 jsm * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58 1.6 jsm * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59 1.6 jsm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60 1.6 jsm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 1.6 jsm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 1.2 mycroft */
63 1.2 mycroft
64 1.4 christos #include <sys/cdefs.h>
65 1.2 mycroft #ifndef lint
66 1.8 dholland __RCSID("$NetBSD: hack.potion.c,v 1.8 2009/08/12 07:28:41 dholland Exp $");
67 1.4 christos #endif /* not lint */
68 1.1 cgd
69 1.1 cgd #include "hack.h"
70 1.4 christos #include "extern.h"
71 1.4 christos
72 1.8 dholland static void ghost_from_bottle(void);
73 1.8 dholland
74 1.4 christos int
75 1.7 dholland dodrink(void)
76 1.4 christos {
77 1.4 christos struct obj *otmp, *objs;
78 1.4 christos struct monst *mtmp;
79 1.4 christos int unkn = 0, nothing = 0;
80 1.1 cgd
81 1.1 cgd otmp = getobj("!", "drink");
82 1.4 christos if (!otmp)
83 1.4 christos return (0);
84 1.4 christos if (!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) {
85 1.1 cgd ghost_from_bottle();
86 1.1 cgd goto use_it;
87 1.1 cgd }
88 1.4 christos switch (otmp->otyp) {
89 1.1 cgd case POT_RESTORE_STRENGTH:
90 1.1 cgd unkn++;
91 1.1 cgd pline("Wow! This makes you feel great!");
92 1.4 christos if (u.ustr < u.ustrmax) {
93 1.1 cgd u.ustr = u.ustrmax;
94 1.1 cgd flags.botl = 1;
95 1.1 cgd }
96 1.1 cgd break;
97 1.1 cgd case POT_BOOZE:
98 1.1 cgd unkn++;
99 1.1 cgd pline("Ooph! This tastes like liquid fire!");
100 1.4 christos Confusion += d(3, 8);
101 1.1 cgd /* the whiskey makes us feel better */
102 1.4 christos if (u.uhp < u.uhpmax)
103 1.4 christos losehp(-1, "bottle of whiskey");
104 1.4 christos if (!rn2(4)) {
105 1.1 cgd pline("You pass out.");
106 1.1 cgd multi = -rnd(15);
107 1.1 cgd nomovemsg = "You awake with a headache.";
108 1.1 cgd }
109 1.1 cgd break;
110 1.1 cgd case POT_INVISIBILITY:
111 1.4 christos if (Invis || See_invisible)
112 1.4 christos nothing++;
113 1.1 cgd else {
114 1.4 christos if (!Blind)
115 1.4 christos pline("Gee! All of a sudden, you can't see yourself.");
116 1.4 christos else
117 1.4 christos pline("You feel rather airy."), unkn++;
118 1.4 christos newsym(u.ux, u.uy);
119 1.1 cgd }
120 1.4 christos Invis += rn1(15, 31);
121 1.1 cgd break;
122 1.1 cgd case POT_FRUIT_JUICE:
123 1.1 cgd pline("This tastes like fruit juice.");
124 1.1 cgd lesshungry(20);
125 1.1 cgd break;
126 1.1 cgd case POT_HEALING:
127 1.1 cgd pline("You begin to feel better.");
128 1.1 cgd flags.botl = 1;
129 1.1 cgd u.uhp += rnd(10);
130 1.4 christos if (u.uhp > u.uhpmax)
131 1.1 cgd u.uhp = ++u.uhpmax;
132 1.4 christos if (Blind)
133 1.4 christos Blind = 1; /* see on next move */
134 1.4 christos if (Sick)
135 1.4 christos Sick = 0;
136 1.1 cgd break;
137 1.1 cgd case POT_PARALYSIS:
138 1.4 christos if (Levitation)
139 1.1 cgd pline("You are motionlessly suspended.");
140 1.1 cgd else
141 1.1 cgd pline("Your feet are frozen to the floor!");
142 1.4 christos nomul(-(rn1(10, 25)));
143 1.1 cgd break;
144 1.1 cgd case POT_MONSTER_DETECTION:
145 1.4 christos if (!fmon) {
146 1.1 cgd strange_feeling(otmp, "You feel threatened.");
147 1.4 christos return (1);
148 1.1 cgd } else {
149 1.1 cgd cls();
150 1.4 christos for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
151 1.4 christos if (mtmp->mx > 0)
152 1.4 christos at(mtmp->mx, mtmp->my, mtmp->data->mlet);
153 1.1 cgd prme();
154 1.1 cgd pline("You sense the presence of monsters.");
155 1.1 cgd more();
156 1.1 cgd docrt();
157 1.1 cgd }
158 1.1 cgd break;
159 1.1 cgd case POT_OBJECT_DETECTION:
160 1.4 christos if (!fobj) {
161 1.1 cgd strange_feeling(otmp, "You feel a pull downward.");
162 1.4 christos return (1);
163 1.1 cgd } else {
164 1.4 christos for (objs = fobj; objs; objs = objs->nobj)
165 1.4 christos if (objs->ox != u.ux || objs->oy != u.uy)
166 1.4 christos goto outobjmap;
167 1.4 christos pline("You sense the presence of objects close nearby.");
168 1.4 christos break;
169 1.4 christos outobjmap:
170 1.1 cgd cls();
171 1.4 christos for (objs = fobj; objs; objs = objs->nobj)
172 1.4 christos at(objs->ox, objs->oy, objs->olet);
173 1.1 cgd prme();
174 1.1 cgd pline("You sense the presence of objects.");
175 1.1 cgd more();
176 1.1 cgd docrt();
177 1.1 cgd }
178 1.1 cgd break;
179 1.1 cgd case POT_SICKNESS:
180 1.1 cgd pline("Yech! This stuff tastes like poison.");
181 1.4 christos if (Poison_resistance)
182 1.4 christos pline("(But in fact it was biologically contaminated orange juice.)");
183 1.4 christos losestr(rn1(4, 3));
184 1.1 cgd losehp(rnd(10), "contaminated potion");
185 1.1 cgd break;
186 1.1 cgd case POT_CONFUSION:
187 1.4 christos if (!Confusion)
188 1.1 cgd pline("Huh, What? Where am I?");
189 1.1 cgd else
190 1.1 cgd nothing++;
191 1.4 christos Confusion += rn1(7, 16);
192 1.1 cgd break;
193 1.1 cgd case POT_GAIN_STRENGTH:
194 1.1 cgd pline("Wow do you feel strong!");
195 1.4 christos if (u.ustr >= 118)
196 1.4 christos break; /* > 118 is impossible */
197 1.4 christos if (u.ustr > 17)
198 1.4 christos u.ustr += rnd(118 - u.ustr);
199 1.4 christos else
200 1.4 christos u.ustr++;
201 1.4 christos if (u.ustr > u.ustrmax)
202 1.4 christos u.ustrmax = u.ustr;
203 1.1 cgd flags.botl = 1;
204 1.1 cgd break;
205 1.1 cgd case POT_SPEED:
206 1.4 christos if (Wounded_legs) {
207 1.1 cgd heal_legs();
208 1.1 cgd unkn++;
209 1.1 cgd break;
210 1.1 cgd }
211 1.4 christos if (!(Fast & ~INTRINSIC))
212 1.1 cgd pline("You are suddenly moving much faster.");
213 1.1 cgd else
214 1.1 cgd pline("Your legs get new energy."), unkn++;
215 1.4 christos Fast += rn1(10, 100);
216 1.1 cgd break;
217 1.1 cgd case POT_BLINDNESS:
218 1.4 christos if (!Blind)
219 1.1 cgd pline("A cloud of darkness falls upon you.");
220 1.1 cgd else
221 1.1 cgd nothing++;
222 1.4 christos Blind += rn1(100, 250);
223 1.1 cgd seeoff(0);
224 1.1 cgd break;
225 1.4 christos case POT_GAIN_LEVEL:
226 1.1 cgd pluslvl();
227 1.1 cgd break;
228 1.1 cgd case POT_EXTRA_HEALING:
229 1.1 cgd pline("You feel much better.");
230 1.1 cgd flags.botl = 1;
231 1.4 christos u.uhp += d(2, 20) + 1;
232 1.4 christos if (u.uhp > u.uhpmax)
233 1.1 cgd u.uhp = (u.uhpmax += 2);
234 1.4 christos if (Blind)
235 1.4 christos Blind = 1;
236 1.4 christos if (Sick)
237 1.4 christos Sick = 0;
238 1.1 cgd break;
239 1.1 cgd case POT_LEVITATION:
240 1.4 christos if (!Levitation)
241 1.1 cgd float_up();
242 1.1 cgd else
243 1.1 cgd nothing++;
244 1.1 cgd Levitation += rnd(100);
245 1.1 cgd u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
246 1.1 cgd break;
247 1.1 cgd default:
248 1.1 cgd impossible("What a funny potion! (%u)", otmp->otyp);
249 1.4 christos return (0);
250 1.1 cgd }
251 1.4 christos if (nothing) {
252 1.4 christos unkn++;
253 1.4 christos pline("You have a peculiar feeling for a moment, then it passes.");
254 1.1 cgd }
255 1.4 christos if (otmp->dknown && !objects[otmp->otyp].oc_name_known) {
256 1.4 christos if (!unkn) {
257 1.1 cgd objects[otmp->otyp].oc_name_known = 1;
258 1.4 christos more_experienced(0, 10);
259 1.4 christos } else if (!objects[otmp->otyp].oc_uname)
260 1.1 cgd docall(otmp);
261 1.1 cgd }
262 1.1 cgd use_it:
263 1.1 cgd useup(otmp);
264 1.4 christos return (1);
265 1.1 cgd }
266 1.1 cgd
267 1.4 christos void
268 1.7 dholland pluslvl(void)
269 1.1 cgd {
270 1.4 christos int num;
271 1.1 cgd
272 1.1 cgd pline("You feel more experienced.");
273 1.1 cgd num = rnd(10);
274 1.1 cgd u.uhpmax += num;
275 1.1 cgd u.uhp += num;
276 1.4 christos if (u.ulevel < 14) {
277 1.4 christos u.uexp = newuexp() + 1;
278 1.1 cgd pline("Welcome to experience level %u.", ++u.ulevel);
279 1.1 cgd }
280 1.1 cgd flags.botl = 1;
281 1.1 cgd }
282 1.1 cgd
283 1.4 christos void
284 1.7 dholland strange_feeling(struct obj *obj, const char *txt)
285 1.1 cgd {
286 1.4 christos if (flags.beginner)
287 1.4 christos pline("You have a strange feeling for a moment, then it passes.");
288 1.1 cgd else
289 1.4 christos pline(txt);
290 1.4 christos if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
291 1.1 cgd docall(obj);
292 1.1 cgd useup(obj);
293 1.1 cgd }
294 1.1 cgd
295 1.8 dholland static const char *const bottlenames[] = {
296 1.1 cgd "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
297 1.1 cgd };
298 1.1 cgd
299 1.4 christos void
300 1.7 dholland potionhit(struct monst *mon, struct obj *obj)
301 1.1 cgd {
302 1.5 jsm const char *botlnam = bottlenames[rn2(SIZE(bottlenames))];
303 1.4 christos boolean uclose, isyou = (mon == &youmonst);
304 1.1 cgd
305 1.4 christos if (isyou) {
306 1.1 cgd uclose = TRUE;
307 1.1 cgd pline("The %s crashes on your head and breaks into shivers.",
308 1.4 christos botlnam);
309 1.1 cgd losehp(rnd(2), "thrown potion");
310 1.1 cgd } else {
311 1.4 christos uclose = (dist(mon->mx, mon->my) < 3);
312 1.1 cgd /* perhaps 'E' and 'a' have no head? */
313 1.1 cgd pline("The %s crashes on %s's head and breaks into shivers.",
314 1.4 christos botlnam, monnam(mon));
315 1.4 christos if (rn2(5) && mon->mhp > 1)
316 1.1 cgd mon->mhp--;
317 1.1 cgd }
318 1.1 cgd pline("The %s evaporates.", xname(obj));
319 1.1 cgd
320 1.4 christos if (!isyou && !rn2(3))
321 1.4 christos switch (obj->otyp) {
322 1.1 cgd
323 1.4 christos case POT_RESTORE_STRENGTH:
324 1.4 christos case POT_GAIN_STRENGTH:
325 1.4 christos case POT_HEALING:
326 1.4 christos case POT_EXTRA_HEALING:
327 1.4 christos if (mon->mhp < mon->mhpmax) {
328 1.4 christos mon->mhp = mon->mhpmax;
329 1.4 christos pline("%s looks sound and hale again!", Monnam(mon));
330 1.4 christos }
331 1.4 christos break;
332 1.4 christos case POT_SICKNESS:
333 1.4 christos if (mon->mhpmax > 3)
334 1.4 christos mon->mhpmax /= 2;
335 1.4 christos if (mon->mhp > 2)
336 1.4 christos mon->mhp /= 2;
337 1.4 christos break;
338 1.4 christos case POT_CONFUSION:
339 1.4 christos case POT_BOOZE:
340 1.4 christos mon->mconf = 1;
341 1.4 christos break;
342 1.4 christos case POT_INVISIBILITY:
343 1.4 christos unpmon(mon);
344 1.4 christos mon->minvis = 1;
345 1.4 christos pmon(mon);
346 1.4 christos break;
347 1.4 christos case POT_PARALYSIS:
348 1.4 christos mon->mfroz = 1;
349 1.4 christos break;
350 1.4 christos case POT_SPEED:
351 1.4 christos mon->mspeed = MFAST;
352 1.4 christos break;
353 1.4 christos case POT_BLINDNESS:
354 1.4 christos mon->mblinded |= 64 + rn2(64);
355 1.4 christos break;
356 1.4 christos /*
357 1.4 christos * case POT_GAIN_LEVEL: case POT_LEVITATION: case
358 1.4 christos * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case
359 1.4 christos * POT_OBJECT_DETECTION: break;
360 1.4 christos */
361 1.1 cgd }
362 1.4 christos if (uclose && rn2(5))
363 1.1 cgd potionbreathe(obj);
364 1.1 cgd obfree(obj, Null(obj));
365 1.1 cgd }
366 1.1 cgd
367 1.4 christos void
368 1.7 dholland potionbreathe(struct obj *obj)
369 1.1 cgd {
370 1.4 christos switch (obj->otyp) {
371 1.1 cgd case POT_RESTORE_STRENGTH:
372 1.1 cgd case POT_GAIN_STRENGTH:
373 1.4 christos if (u.ustr < u.ustrmax)
374 1.4 christos u.ustr++, flags.botl = 1;
375 1.1 cgd break;
376 1.1 cgd case POT_HEALING:
377 1.1 cgd case POT_EXTRA_HEALING:
378 1.4 christos if (u.uhp < u.uhpmax)
379 1.4 christos u.uhp++, flags.botl = 1;
380 1.1 cgd break;
381 1.1 cgd case POT_SICKNESS:
382 1.4 christos if (u.uhp <= 5)
383 1.4 christos u.uhp = 1;
384 1.4 christos else
385 1.4 christos u.uhp -= 5;
386 1.1 cgd flags.botl = 1;
387 1.1 cgd break;
388 1.1 cgd case POT_CONFUSION:
389 1.1 cgd case POT_BOOZE:
390 1.4 christos if (!Confusion)
391 1.1 cgd pline("You feel somewhat dizzy.");
392 1.1 cgd Confusion += rnd(5);
393 1.1 cgd break;
394 1.1 cgd case POT_INVISIBILITY:
395 1.1 cgd pline("For an instant you couldn't see your right hand.");
396 1.1 cgd break;
397 1.1 cgd case POT_PARALYSIS:
398 1.1 cgd pline("Something seems to be holding you.");
399 1.1 cgd nomul(-rnd(5));
400 1.1 cgd break;
401 1.1 cgd case POT_SPEED:
402 1.1 cgd Fast += rnd(5);
403 1.1 cgd pline("Your knees seem more flexible now.");
404 1.1 cgd break;
405 1.1 cgd case POT_BLINDNESS:
406 1.4 christos if (!Blind)
407 1.4 christos pline("It suddenly gets dark.");
408 1.1 cgd Blind += rnd(5);
409 1.1 cgd seeoff(0);
410 1.1 cgd break;
411 1.4 christos /*
412 1.4 christos * case POT_GAIN_LEVEL: case POT_LEVITATION: case
413 1.4 christos * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case
414 1.4 christos * POT_OBJECT_DETECTION: break;
415 1.4 christos */
416 1.1 cgd }
417 1.1 cgd /* note: no obfree() */
418 1.1 cgd }
419 1.1 cgd
420 1.1 cgd /*
421 1.1 cgd * -- rudimentary -- to do this correctly requires much more work
422 1.1 cgd * -- all sharp weapons get one or more qualities derived from the potions
423 1.1 cgd * -- texts on scrolls may be (partially) wiped out; do they become blank?
424 1.1 cgd * -- or does their effect change, like under Confusion?
425 1.1 cgd * -- all objects may be made invisible by POT_INVISIBILITY
426 1.1 cgd * -- If the flask is small, can one dip a large object? Does it magically
427 1.1 cgd * -- become a jug? Etc.
428 1.1 cgd */
429 1.4 christos int
430 1.7 dholland dodip(void)
431 1.4 christos {
432 1.4 christos struct obj *potion, *obj;
433 1.1 cgd
434 1.4 christos if (!(obj = getobj("#", "dip")))
435 1.4 christos return (0);
436 1.4 christos if (!(potion = getobj("!", "dip into")))
437 1.4 christos return (0);
438 1.1 cgd pline("Interesting...");
439 1.4 christos if (obj->otyp == ARROW || obj->otyp == DART ||
440 1.4 christos obj->otyp == CROSSBOW_BOLT) {
441 1.4 christos if (potion->otyp == POT_SICKNESS) {
442 1.1 cgd useup(potion);
443 1.4 christos if (obj->spe < 7)
444 1.4 christos obj->spe++; /* %% */
445 1.1 cgd }
446 1.1 cgd }
447 1.4 christos return (1);
448 1.1 cgd }
449 1.1 cgd
450 1.8 dholland static void
451 1.7 dholland ghost_from_bottle(void)
452 1.4 christos {
453 1.4 christos struct monst *mtmp;
454 1.1 cgd
455 1.4 christos if (!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) {
456 1.1 cgd pline("This bottle turns out to be empty.");
457 1.1 cgd return;
458 1.1 cgd }
459 1.1 cgd mnexto(mtmp);
460 1.1 cgd pline("As you open the bottle, an enormous ghost emerges!");
461 1.1 cgd pline("You are frightened to death, and unable to move.");
462 1.1 cgd nomul(-3);
463 1.1 cgd }
464