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