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