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