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