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