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