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