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