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