1 /* $NetBSD: hack.potion.c,v 1.6 2003/04/02 18:36:39 jsm 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.6 2003/04/02 18:36:39 jsm Exp $"); 67 #endif /* not lint */ 68 69 #include "hack.h" 70 #include "extern.h" 71 72 int 73 dodrink() 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() 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(obj, txt) 283 struct obj *obj; 284 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(txt); 290 if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) 291 docall(obj); 292 useup(obj); 293 } 294 295 const char *const bottlenames[] = { 296 "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial" 297 }; 298 299 void 300 potionhit(mon, obj) 301 struct monst *mon; 302 struct obj *obj; 303 { 304 const char *botlnam = bottlenames[rn2(SIZE(bottlenames))]; 305 boolean uclose, isyou = (mon == &youmonst); 306 307 if (isyou) { 308 uclose = TRUE; 309 pline("The %s crashes on your head and breaks into shivers.", 310 botlnam); 311 losehp(rnd(2), "thrown potion"); 312 } else { 313 uclose = (dist(mon->mx, mon->my) < 3); 314 /* perhaps 'E' and 'a' have no head? */ 315 pline("The %s crashes on %s's head and breaks into shivers.", 316 botlnam, monnam(mon)); 317 if (rn2(5) && mon->mhp > 1) 318 mon->mhp--; 319 } 320 pline("The %s evaporates.", xname(obj)); 321 322 if (!isyou && !rn2(3)) 323 switch (obj->otyp) { 324 325 case POT_RESTORE_STRENGTH: 326 case POT_GAIN_STRENGTH: 327 case POT_HEALING: 328 case POT_EXTRA_HEALING: 329 if (mon->mhp < mon->mhpmax) { 330 mon->mhp = mon->mhpmax; 331 pline("%s looks sound and hale again!", Monnam(mon)); 332 } 333 break; 334 case POT_SICKNESS: 335 if (mon->mhpmax > 3) 336 mon->mhpmax /= 2; 337 if (mon->mhp > 2) 338 mon->mhp /= 2; 339 break; 340 case POT_CONFUSION: 341 case POT_BOOZE: 342 mon->mconf = 1; 343 break; 344 case POT_INVISIBILITY: 345 unpmon(mon); 346 mon->minvis = 1; 347 pmon(mon); 348 break; 349 case POT_PARALYSIS: 350 mon->mfroz = 1; 351 break; 352 case POT_SPEED: 353 mon->mspeed = MFAST; 354 break; 355 case POT_BLINDNESS: 356 mon->mblinded |= 64 + rn2(64); 357 break; 358 /* 359 * case POT_GAIN_LEVEL: case POT_LEVITATION: case 360 * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case 361 * POT_OBJECT_DETECTION: break; 362 */ 363 } 364 if (uclose && rn2(5)) 365 potionbreathe(obj); 366 obfree(obj, Null(obj)); 367 } 368 369 void 370 potionbreathe(obj) 371 struct obj *obj; 372 { 373 switch (obj->otyp) { 374 case POT_RESTORE_STRENGTH: 375 case POT_GAIN_STRENGTH: 376 if (u.ustr < u.ustrmax) 377 u.ustr++, flags.botl = 1; 378 break; 379 case POT_HEALING: 380 case POT_EXTRA_HEALING: 381 if (u.uhp < u.uhpmax) 382 u.uhp++, flags.botl = 1; 383 break; 384 case POT_SICKNESS: 385 if (u.uhp <= 5) 386 u.uhp = 1; 387 else 388 u.uhp -= 5; 389 flags.botl = 1; 390 break; 391 case POT_CONFUSION: 392 case POT_BOOZE: 393 if (!Confusion) 394 pline("You feel somewhat dizzy."); 395 Confusion += rnd(5); 396 break; 397 case POT_INVISIBILITY: 398 pline("For an instant you couldn't see your right hand."); 399 break; 400 case POT_PARALYSIS: 401 pline("Something seems to be holding you."); 402 nomul(-rnd(5)); 403 break; 404 case POT_SPEED: 405 Fast += rnd(5); 406 pline("Your knees seem more flexible now."); 407 break; 408 case POT_BLINDNESS: 409 if (!Blind) 410 pline("It suddenly gets dark."); 411 Blind += rnd(5); 412 seeoff(0); 413 break; 414 /* 415 * case POT_GAIN_LEVEL: case POT_LEVITATION: case 416 * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case 417 * POT_OBJECT_DETECTION: break; 418 */ 419 } 420 /* note: no obfree() */ 421 } 422 423 /* 424 * -- rudimentary -- to do this correctly requires much more work 425 * -- all sharp weapons get one or more qualities derived from the potions 426 * -- texts on scrolls may be (partially) wiped out; do they become blank? 427 * -- or does their effect change, like under Confusion? 428 * -- all objects may be made invisible by POT_INVISIBILITY 429 * -- If the flask is small, can one dip a large object? Does it magically 430 * -- become a jug? Etc. 431 */ 432 int 433 dodip() 434 { 435 struct obj *potion, *obj; 436 437 if (!(obj = getobj("#", "dip"))) 438 return (0); 439 if (!(potion = getobj("!", "dip into"))) 440 return (0); 441 pline("Interesting..."); 442 if (obj->otyp == ARROW || obj->otyp == DART || 443 obj->otyp == CROSSBOW_BOLT) { 444 if (potion->otyp == POT_SICKNESS) { 445 useup(potion); 446 if (obj->spe < 7) 447 obj->spe++; /* %% */ 448 } 449 } 450 return (1); 451 } 452 453 void 454 ghost_from_bottle() 455 { 456 struct monst *mtmp; 457 458 if (!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) { 459 pline("This bottle turns out to be empty."); 460 return; 461 } 462 mnexto(mtmp); 463 pline("As you open the bottle, an enormous ghost emerges!"); 464 pline("You are frightened to death, and unable to move."); 465 nomul(-3); 466 } 467