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