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