1 1.9 joerg /* $NetBSD: hack.potion.c,v 1.9 2011/05/23 22:53:25 joerg Exp $ */ 2 1.4 christos 3 1.2 mycroft /* 4 1.6 jsm * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 1.6 jsm * Amsterdam 6 1.6 jsm * All rights reserved. 7 1.6 jsm * 8 1.6 jsm * Redistribution and use in source and binary forms, with or without 9 1.6 jsm * modification, are permitted provided that the following conditions are 10 1.6 jsm * met: 11 1.6 jsm * 12 1.6 jsm * - Redistributions of source code must retain the above copyright notice, 13 1.6 jsm * this list of conditions and the following disclaimer. 14 1.6 jsm * 15 1.6 jsm * - Redistributions in binary form must reproduce the above copyright 16 1.6 jsm * notice, this list of conditions and the following disclaimer in the 17 1.6 jsm * documentation and/or other materials provided with the distribution. 18 1.6 jsm * 19 1.6 jsm * - Neither the name of the Stichting Centrum voor Wiskunde en 20 1.6 jsm * Informatica, nor the names of its contributors may be used to endorse or 21 1.6 jsm * promote products derived from this software without specific prior 22 1.6 jsm * written permission. 23 1.6 jsm * 24 1.6 jsm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 1.6 jsm * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 1.6 jsm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 1.6 jsm * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 1.6 jsm * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 1.6 jsm * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 1.6 jsm * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 1.6 jsm * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 1.6 jsm * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 1.6 jsm */ 36 1.6 jsm 37 1.6 jsm /* 38 1.6 jsm * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org> 39 1.6 jsm * All rights reserved. 40 1.6 jsm * 41 1.6 jsm * Redistribution and use in source and binary forms, with or without 42 1.6 jsm * modification, are permitted provided that the following conditions 43 1.6 jsm * are met: 44 1.6 jsm * 1. Redistributions of source code must retain the above copyright 45 1.6 jsm * notice, this list of conditions and the following disclaimer. 46 1.6 jsm * 2. Redistributions in binary form must reproduce the above copyright 47 1.6 jsm * notice, this list of conditions and the following disclaimer in the 48 1.6 jsm * documentation and/or other materials provided with the distribution. 49 1.6 jsm * 3. The name of the author may not be used to endorse or promote products 50 1.6 jsm * derived from this software without specific prior written permission. 51 1.6 jsm * 52 1.6 jsm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 1.6 jsm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 1.6 jsm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 1.6 jsm * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 1.6 jsm * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 1.6 jsm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 1.6 jsm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 1.6 jsm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 1.2 mycroft */ 63 1.2 mycroft 64 1.4 christos #include <sys/cdefs.h> 65 1.2 mycroft #ifndef lint 66 1.9 joerg __RCSID("$NetBSD: hack.potion.c,v 1.9 2011/05/23 22:53:25 joerg Exp $"); 67 1.4 christos #endif /* not lint */ 68 1.1 cgd 69 1.1 cgd #include "hack.h" 70 1.4 christos #include "extern.h" 71 1.4 christos 72 1.8 dholland static void ghost_from_bottle(void); 73 1.8 dholland 74 1.4 christos int 75 1.7 dholland dodrink(void) 76 1.4 christos { 77 1.4 christos struct obj *otmp, *objs; 78 1.4 christos struct monst *mtmp; 79 1.4 christos int unkn = 0, nothing = 0; 80 1.1 cgd 81 1.1 cgd otmp = getobj("!", "drink"); 82 1.4 christos if (!otmp) 83 1.4 christos return (0); 84 1.4 christos if (!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) { 85 1.1 cgd ghost_from_bottle(); 86 1.1 cgd goto use_it; 87 1.1 cgd } 88 1.4 christos switch (otmp->otyp) { 89 1.1 cgd case POT_RESTORE_STRENGTH: 90 1.1 cgd unkn++; 91 1.1 cgd pline("Wow! This makes you feel great!"); 92 1.4 christos if (u.ustr < u.ustrmax) { 93 1.1 cgd u.ustr = u.ustrmax; 94 1.1 cgd flags.botl = 1; 95 1.1 cgd } 96 1.1 cgd break; 97 1.1 cgd case POT_BOOZE: 98 1.1 cgd unkn++; 99 1.1 cgd pline("Ooph! This tastes like liquid fire!"); 100 1.4 christos Confusion += d(3, 8); 101 1.1 cgd /* the whiskey makes us feel better */ 102 1.4 christos if (u.uhp < u.uhpmax) 103 1.4 christos losehp(-1, "bottle of whiskey"); 104 1.4 christos if (!rn2(4)) { 105 1.1 cgd pline("You pass out."); 106 1.1 cgd multi = -rnd(15); 107 1.1 cgd nomovemsg = "You awake with a headache."; 108 1.1 cgd } 109 1.1 cgd break; 110 1.1 cgd case POT_INVISIBILITY: 111 1.4 christos if (Invis || See_invisible) 112 1.4 christos nothing++; 113 1.1 cgd else { 114 1.4 christos if (!Blind) 115 1.4 christos pline("Gee! All of a sudden, you can't see yourself."); 116 1.4 christos else 117 1.4 christos pline("You feel rather airy."), unkn++; 118 1.4 christos newsym(u.ux, u.uy); 119 1.1 cgd } 120 1.4 christos Invis += rn1(15, 31); 121 1.1 cgd break; 122 1.1 cgd case POT_FRUIT_JUICE: 123 1.1 cgd pline("This tastes like fruit juice."); 124 1.1 cgd lesshungry(20); 125 1.1 cgd break; 126 1.1 cgd case POT_HEALING: 127 1.1 cgd pline("You begin to feel better."); 128 1.1 cgd flags.botl = 1; 129 1.1 cgd u.uhp += rnd(10); 130 1.4 christos if (u.uhp > u.uhpmax) 131 1.1 cgd u.uhp = ++u.uhpmax; 132 1.4 christos if (Blind) 133 1.4 christos Blind = 1; /* see on next move */ 134 1.4 christos if (Sick) 135 1.4 christos Sick = 0; 136 1.1 cgd break; 137 1.1 cgd case POT_PARALYSIS: 138 1.4 christos if (Levitation) 139 1.1 cgd pline("You are motionlessly suspended."); 140 1.1 cgd else 141 1.1 cgd pline("Your feet are frozen to the floor!"); 142 1.4 christos nomul(-(rn1(10, 25))); 143 1.1 cgd break; 144 1.1 cgd case POT_MONSTER_DETECTION: 145 1.4 christos if (!fmon) { 146 1.1 cgd strange_feeling(otmp, "You feel threatened."); 147 1.4 christos return (1); 148 1.1 cgd } else { 149 1.1 cgd cls(); 150 1.4 christos for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 151 1.4 christos if (mtmp->mx > 0) 152 1.4 christos at(mtmp->mx, mtmp->my, mtmp->data->mlet); 153 1.1 cgd prme(); 154 1.1 cgd pline("You sense the presence of monsters."); 155 1.1 cgd more(); 156 1.1 cgd docrt(); 157 1.1 cgd } 158 1.1 cgd break; 159 1.1 cgd case POT_OBJECT_DETECTION: 160 1.4 christos if (!fobj) { 161 1.1 cgd strange_feeling(otmp, "You feel a pull downward."); 162 1.4 christos return (1); 163 1.1 cgd } else { 164 1.4 christos for (objs = fobj; objs; objs = objs->nobj) 165 1.4 christos if (objs->ox != u.ux || objs->oy != u.uy) 166 1.4 christos goto outobjmap; 167 1.4 christos pline("You sense the presence of objects close nearby."); 168 1.4 christos break; 169 1.4 christos outobjmap: 170 1.1 cgd cls(); 171 1.4 christos for (objs = fobj; objs; objs = objs->nobj) 172 1.4 christos at(objs->ox, objs->oy, objs->olet); 173 1.1 cgd prme(); 174 1.1 cgd pline("You sense the presence of objects."); 175 1.1 cgd more(); 176 1.1 cgd docrt(); 177 1.1 cgd } 178 1.1 cgd break; 179 1.1 cgd case POT_SICKNESS: 180 1.1 cgd pline("Yech! This stuff tastes like poison."); 181 1.4 christos if (Poison_resistance) 182 1.4 christos pline("(But in fact it was biologically contaminated orange juice.)"); 183 1.4 christos losestr(rn1(4, 3)); 184 1.1 cgd losehp(rnd(10), "contaminated potion"); 185 1.1 cgd break; 186 1.1 cgd case POT_CONFUSION: 187 1.4 christos if (!Confusion) 188 1.1 cgd pline("Huh, What? Where am I?"); 189 1.1 cgd else 190 1.1 cgd nothing++; 191 1.4 christos Confusion += rn1(7, 16); 192 1.1 cgd break; 193 1.1 cgd case POT_GAIN_STRENGTH: 194 1.1 cgd pline("Wow do you feel strong!"); 195 1.4 christos if (u.ustr >= 118) 196 1.4 christos break; /* > 118 is impossible */ 197 1.4 christos if (u.ustr > 17) 198 1.4 christos u.ustr += rnd(118 - u.ustr); 199 1.4 christos else 200 1.4 christos u.ustr++; 201 1.4 christos if (u.ustr > u.ustrmax) 202 1.4 christos u.ustrmax = u.ustr; 203 1.1 cgd flags.botl = 1; 204 1.1 cgd break; 205 1.1 cgd case POT_SPEED: 206 1.4 christos if (Wounded_legs) { 207 1.1 cgd heal_legs(); 208 1.1 cgd unkn++; 209 1.1 cgd break; 210 1.1 cgd } 211 1.4 christos if (!(Fast & ~INTRINSIC)) 212 1.1 cgd pline("You are suddenly moving much faster."); 213 1.1 cgd else 214 1.1 cgd pline("Your legs get new energy."), unkn++; 215 1.4 christos Fast += rn1(10, 100); 216 1.1 cgd break; 217 1.1 cgd case POT_BLINDNESS: 218 1.4 christos if (!Blind) 219 1.1 cgd pline("A cloud of darkness falls upon you."); 220 1.1 cgd else 221 1.1 cgd nothing++; 222 1.4 christos Blind += rn1(100, 250); 223 1.1 cgd seeoff(0); 224 1.1 cgd break; 225 1.4 christos case POT_GAIN_LEVEL: 226 1.1 cgd pluslvl(); 227 1.1 cgd break; 228 1.1 cgd case POT_EXTRA_HEALING: 229 1.1 cgd pline("You feel much better."); 230 1.1 cgd flags.botl = 1; 231 1.4 christos u.uhp += d(2, 20) + 1; 232 1.4 christos if (u.uhp > u.uhpmax) 233 1.1 cgd u.uhp = (u.uhpmax += 2); 234 1.4 christos if (Blind) 235 1.4 christos Blind = 1; 236 1.4 christos if (Sick) 237 1.4 christos Sick = 0; 238 1.1 cgd break; 239 1.1 cgd case POT_LEVITATION: 240 1.4 christos if (!Levitation) 241 1.1 cgd float_up(); 242 1.1 cgd else 243 1.1 cgd nothing++; 244 1.1 cgd Levitation += rnd(100); 245 1.1 cgd u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down; 246 1.1 cgd break; 247 1.1 cgd default: 248 1.1 cgd impossible("What a funny potion! (%u)", otmp->otyp); 249 1.4 christos return (0); 250 1.1 cgd } 251 1.4 christos if (nothing) { 252 1.4 christos unkn++; 253 1.4 christos pline("You have a peculiar feeling for a moment, then it passes."); 254 1.1 cgd } 255 1.4 christos if (otmp->dknown && !objects[otmp->otyp].oc_name_known) { 256 1.4 christos if (!unkn) { 257 1.1 cgd objects[otmp->otyp].oc_name_known = 1; 258 1.4 christos more_experienced(0, 10); 259 1.4 christos } else if (!objects[otmp->otyp].oc_uname) 260 1.1 cgd docall(otmp); 261 1.1 cgd } 262 1.1 cgd use_it: 263 1.1 cgd useup(otmp); 264 1.4 christos return (1); 265 1.1 cgd } 266 1.1 cgd 267 1.4 christos void 268 1.7 dholland pluslvl(void) 269 1.1 cgd { 270 1.4 christos int num; 271 1.1 cgd 272 1.1 cgd pline("You feel more experienced."); 273 1.1 cgd num = rnd(10); 274 1.1 cgd u.uhpmax += num; 275 1.1 cgd u.uhp += num; 276 1.4 christos if (u.ulevel < 14) { 277 1.4 christos u.uexp = newuexp() + 1; 278 1.1 cgd pline("Welcome to experience level %u.", ++u.ulevel); 279 1.1 cgd } 280 1.1 cgd flags.botl = 1; 281 1.1 cgd } 282 1.1 cgd 283 1.4 christos void 284 1.7 dholland strange_feeling(struct obj *obj, const char *txt) 285 1.1 cgd { 286 1.4 christos if (flags.beginner) 287 1.4 christos pline("You have a strange feeling for a moment, then it passes."); 288 1.1 cgd else 289 1.9 joerg pline("%s", txt); 290 1.4 christos if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) 291 1.1 cgd docall(obj); 292 1.1 cgd useup(obj); 293 1.1 cgd } 294 1.1 cgd 295 1.8 dholland static const char *const bottlenames[] = { 296 1.1 cgd "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial" 297 1.1 cgd }; 298 1.1 cgd 299 1.4 christos void 300 1.7 dholland potionhit(struct monst *mon, struct obj *obj) 301 1.1 cgd { 302 1.5 jsm const char *botlnam = bottlenames[rn2(SIZE(bottlenames))]; 303 1.4 christos boolean uclose, isyou = (mon == &youmonst); 304 1.1 cgd 305 1.4 christos if (isyou) { 306 1.1 cgd uclose = TRUE; 307 1.1 cgd pline("The %s crashes on your head and breaks into shivers.", 308 1.4 christos botlnam); 309 1.1 cgd losehp(rnd(2), "thrown potion"); 310 1.1 cgd } else { 311 1.4 christos uclose = (dist(mon->mx, mon->my) < 3); 312 1.1 cgd /* perhaps 'E' and 'a' have no head? */ 313 1.1 cgd pline("The %s crashes on %s's head and breaks into shivers.", 314 1.4 christos botlnam, monnam(mon)); 315 1.4 christos if (rn2(5) && mon->mhp > 1) 316 1.1 cgd mon->mhp--; 317 1.1 cgd } 318 1.1 cgd pline("The %s evaporates.", xname(obj)); 319 1.1 cgd 320 1.4 christos if (!isyou && !rn2(3)) 321 1.4 christos switch (obj->otyp) { 322 1.1 cgd 323 1.4 christos case POT_RESTORE_STRENGTH: 324 1.4 christos case POT_GAIN_STRENGTH: 325 1.4 christos case POT_HEALING: 326 1.4 christos case POT_EXTRA_HEALING: 327 1.4 christos if (mon->mhp < mon->mhpmax) { 328 1.4 christos mon->mhp = mon->mhpmax; 329 1.4 christos pline("%s looks sound and hale again!", Monnam(mon)); 330 1.4 christos } 331 1.4 christos break; 332 1.4 christos case POT_SICKNESS: 333 1.4 christos if (mon->mhpmax > 3) 334 1.4 christos mon->mhpmax /= 2; 335 1.4 christos if (mon->mhp > 2) 336 1.4 christos mon->mhp /= 2; 337 1.4 christos break; 338 1.4 christos case POT_CONFUSION: 339 1.4 christos case POT_BOOZE: 340 1.4 christos mon->mconf = 1; 341 1.4 christos break; 342 1.4 christos case POT_INVISIBILITY: 343 1.4 christos unpmon(mon); 344 1.4 christos mon->minvis = 1; 345 1.4 christos pmon(mon); 346 1.4 christos break; 347 1.4 christos case POT_PARALYSIS: 348 1.4 christos mon->mfroz = 1; 349 1.4 christos break; 350 1.4 christos case POT_SPEED: 351 1.4 christos mon->mspeed = MFAST; 352 1.4 christos break; 353 1.4 christos case POT_BLINDNESS: 354 1.4 christos mon->mblinded |= 64 + rn2(64); 355 1.4 christos break; 356 1.4 christos /* 357 1.4 christos * case POT_GAIN_LEVEL: case POT_LEVITATION: case 358 1.4 christos * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case 359 1.4 christos * POT_OBJECT_DETECTION: break; 360 1.4 christos */ 361 1.1 cgd } 362 1.4 christos if (uclose && rn2(5)) 363 1.1 cgd potionbreathe(obj); 364 1.1 cgd obfree(obj, Null(obj)); 365 1.1 cgd } 366 1.1 cgd 367 1.4 christos void 368 1.7 dholland potionbreathe(struct obj *obj) 369 1.1 cgd { 370 1.4 christos switch (obj->otyp) { 371 1.1 cgd case POT_RESTORE_STRENGTH: 372 1.1 cgd case POT_GAIN_STRENGTH: 373 1.4 christos if (u.ustr < u.ustrmax) 374 1.4 christos u.ustr++, flags.botl = 1; 375 1.1 cgd break; 376 1.1 cgd case POT_HEALING: 377 1.1 cgd case POT_EXTRA_HEALING: 378 1.4 christos if (u.uhp < u.uhpmax) 379 1.4 christos u.uhp++, flags.botl = 1; 380 1.1 cgd break; 381 1.1 cgd case POT_SICKNESS: 382 1.4 christos if (u.uhp <= 5) 383 1.4 christos u.uhp = 1; 384 1.4 christos else 385 1.4 christos u.uhp -= 5; 386 1.1 cgd flags.botl = 1; 387 1.1 cgd break; 388 1.1 cgd case POT_CONFUSION: 389 1.1 cgd case POT_BOOZE: 390 1.4 christos if (!Confusion) 391 1.1 cgd pline("You feel somewhat dizzy."); 392 1.1 cgd Confusion += rnd(5); 393 1.1 cgd break; 394 1.1 cgd case POT_INVISIBILITY: 395 1.1 cgd pline("For an instant you couldn't see your right hand."); 396 1.1 cgd break; 397 1.1 cgd case POT_PARALYSIS: 398 1.1 cgd pline("Something seems to be holding you."); 399 1.1 cgd nomul(-rnd(5)); 400 1.1 cgd break; 401 1.1 cgd case POT_SPEED: 402 1.1 cgd Fast += rnd(5); 403 1.1 cgd pline("Your knees seem more flexible now."); 404 1.1 cgd break; 405 1.1 cgd case POT_BLINDNESS: 406 1.4 christos if (!Blind) 407 1.4 christos pline("It suddenly gets dark."); 408 1.1 cgd Blind += rnd(5); 409 1.1 cgd seeoff(0); 410 1.1 cgd break; 411 1.4 christos /* 412 1.4 christos * case POT_GAIN_LEVEL: case POT_LEVITATION: case 413 1.4 christos * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case 414 1.4 christos * POT_OBJECT_DETECTION: break; 415 1.4 christos */ 416 1.1 cgd } 417 1.1 cgd /* note: no obfree() */ 418 1.1 cgd } 419 1.1 cgd 420 1.1 cgd /* 421 1.1 cgd * -- rudimentary -- to do this correctly requires much more work 422 1.1 cgd * -- all sharp weapons get one or more qualities derived from the potions 423 1.1 cgd * -- texts on scrolls may be (partially) wiped out; do they become blank? 424 1.1 cgd * -- or does their effect change, like under Confusion? 425 1.1 cgd * -- all objects may be made invisible by POT_INVISIBILITY 426 1.1 cgd * -- If the flask is small, can one dip a large object? Does it magically 427 1.1 cgd * -- become a jug? Etc. 428 1.1 cgd */ 429 1.4 christos int 430 1.7 dholland dodip(void) 431 1.4 christos { 432 1.4 christos struct obj *potion, *obj; 433 1.1 cgd 434 1.4 christos if (!(obj = getobj("#", "dip"))) 435 1.4 christos return (0); 436 1.4 christos if (!(potion = getobj("!", "dip into"))) 437 1.4 christos return (0); 438 1.1 cgd pline("Interesting..."); 439 1.4 christos if (obj->otyp == ARROW || obj->otyp == DART || 440 1.4 christos obj->otyp == CROSSBOW_BOLT) { 441 1.4 christos if (potion->otyp == POT_SICKNESS) { 442 1.1 cgd useup(potion); 443 1.4 christos if (obj->spe < 7) 444 1.4 christos obj->spe++; /* %% */ 445 1.1 cgd } 446 1.1 cgd } 447 1.4 christos return (1); 448 1.1 cgd } 449 1.1 cgd 450 1.8 dholland static void 451 1.7 dholland ghost_from_bottle(void) 452 1.4 christos { 453 1.4 christos struct monst *mtmp; 454 1.1 cgd 455 1.4 christos if (!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) { 456 1.1 cgd pline("This bottle turns out to be empty."); 457 1.1 cgd return; 458 1.1 cgd } 459 1.1 cgd mnexto(mtmp); 460 1.1 cgd pline("As you open the bottle, an enormous ghost emerges!"); 461 1.1 cgd pline("You are frightened to death, and unable to move."); 462 1.1 cgd nomul(-3); 463 1.1 cgd } 464