1 /*	SCCS Id: @(#)fountain.c	3.4	2003/03/23	*/
2 /*	Copyright Scott R. Turner, srt@ucla, 10/27/86 */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /* Code for drinking from fountains. */
6 
7 #include "hack.h"
8 
9 STATIC_DCL void NDECL(dowatersnakes);
10 STATIC_DCL void NDECL(dowaterdemon);
11 STATIC_DCL void NDECL(dowaternymph);
12 STATIC_PTR void FDECL(gush, (int,int,genericptr_t));
13 STATIC_DCL void NDECL(dofindgem);
14 
15 void
floating_above(what)16 floating_above(what)
17 const char *what;
18 {
19     You("are floating high above the %s.", what);
20 }
21 
22 STATIC_OVL void
dowatersnakes()23 dowatersnakes() /* Fountain of snakes! */
24 {
25     register int num = rn1(5,2);
26     struct monst *mtmp;
27 
28     if (!(mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) {
29 	if (!Blind)
30 	    pline("An endless stream of %s pours forth!",
31 		  Hallucination ? makeplural(rndmonnam()) : "snakes");
32 	else
33 	    You_hear("%s hissing!", something);
34 	while(num-- > 0)
35 	    if((mtmp = makemon(&mons[PM_WATER_MOCCASIN],
36 			u.ux, u.uy, NO_MM_FLAGS)) && t_at(mtmp->mx, mtmp->my))
37 		(void) mintrap(mtmp);
38     } else
39 	pline_The("fountain bubbles furiously for a moment, then calms.");
40 }
41 
42 STATIC_OVL
43 void
dowaterdemon()44 dowaterdemon() /* Water demon */
45 {
46     register struct monst *mtmp;
47 
48     if(!(mvitals[PM_WATER_DEMON].mvflags & G_GONE)) {
49 	if((mtmp = makemon(&mons[PM_WATER_DEMON],u.ux,u.uy, NO_MM_FLAGS))) {
50 	    if (!Blind)
51 		You("unleash %s!", a_monnam(mtmp));
52 	    else
53 		You_feel("the presence of evil.");
54 
55 	/* Give those on low levels a (slightly) better chance of survival */
56 	    if (rnd(100) > (80 + level_difficulty())) {
57 		pline("Grateful for %s release, %s grants you a wish!",
58 		      mhis(mtmp), mhe(mtmp));
59 		makewish(FALSE);
60 		mongone(mtmp);
61 	    } else if (t_at(mtmp->mx, mtmp->my))
62 		(void) mintrap(mtmp);
63 	}
64     } else
65 	pline_The("fountain bubbles furiously for a moment, then calms.");
66 }
67 
68 STATIC_OVL void
dowaternymph()69 dowaternymph() /* Water Nymph */
70 {
71 	register struct monst *mtmp;
72 
73 	if(!(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) &&
74 	   (mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) {
75 		if (!Blind)
76 		   You("attract %s!", a_monnam(mtmp));
77 		else
78 		   You_hear("a seductive voice.");
79 		mtmp->msleeping = 0;
80 		if (t_at(mtmp->mx, mtmp->my))
81 		    (void) mintrap(mtmp);
82 	} else
83 		if (!Blind)
84 		   pline("A large bubble rises to the surface and pops.");
85 		else
86 		   You_hear("a loud pop.");
87 }
88 
89 void
dogushforth(drinking)90 dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */
91 int drinking;
92 {
93 	int madepool = 0;
94 
95 	do_clear_area(u.ux, u.uy, 7, gush, (genericptr_t)&madepool);
96 	if (!madepool) {
97 	    if (drinking)
98 		Your("thirst is quenched.");
99 	    else
100 		pline("Water sprays all over you.");
101 	}
102 }
103 
104 STATIC_PTR void
gush(x,y,poolcnt)105 gush(x, y, poolcnt)
106 int x, y;
107 genericptr_t poolcnt;
108 {
109 	register struct monst *mtmp;
110 	register struct trap *ttmp;
111 
112 	if (((x+y)%2) || (x == u.ux && y == u.uy) ||
113 	    (rn2(1 + distmin(u.ux, u.uy, x, y)))  ||
114 	    (levl[x][y].typ != ROOM) ||
115 	    (sobj_at(BOULDER, x, y)) || nexttodoor(x, y))
116 		return;
117 
118 	if ((ttmp = t_at(x, y)) != 0 && !delfloortrap(ttmp))
119 		return;
120 
121 	if (!((*(int *)poolcnt)++))
122 	    pline("Water gushes forth from the overflowing fountain!");
123 
124 	/* Put a pool at x, y */
125 	levl[x][y].typ = POOL;
126 	/* No kelp! */
127 	del_engr_at(x, y);
128 	water_damage(level.objects[x][y], FALSE, TRUE);
129 
130 	if ((mtmp = m_at(x, y)) != 0)
131 		(void) minliquid(mtmp);
132 	else
133 		newsym(x,y);
134 }
135 
136 STATIC_OVL void
dofindgem()137 dofindgem() /* Find a gem in the sparkling waters. */
138 {
139 	if (!Blind) You("spot a gem in the sparkling waters!");
140 	else You_feel("a gem here!");
141 	(void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1),
142 			 u.ux, u.uy, FALSE, FALSE);
143 	SET_FOUNTAIN_LOOTED(u.ux,u.uy);
144 	newsym(u.ux, u.uy);
145 	exercise(A_WIS, TRUE);			/* a discovery! */
146 }
147 
148 void
dryup(x,y,isyou)149 dryup(x, y, isyou)
150 xchar x, y;
151 boolean isyou;
152 {
153 	if (IS_FOUNTAIN(levl[x][y].typ) &&
154 	    (!rn2(3) || FOUNTAIN_IS_WARNED(x,y))) {
155 		if(isyou && in_town(x, y) && !FOUNTAIN_IS_WARNED(x,y)) {
156 			struct monst *mtmp;
157 			SET_FOUNTAIN_WARNED(x,y);
158 			/* Warn about future fountain use. */
159 			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
160 			    if (DEADMONSTER(mtmp)) continue;
161 			    if ((mtmp->data == &mons[PM_WATCHMAN] ||
162 				mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
163 			       couldsee(mtmp->mx, mtmp->my) &&
164 			       mtmp->mpeaceful) {
165 				pline("%s yells:", Amonnam(mtmp));
166 				verbalize("Hey, stop using that fountain!");
167 				break;
168 			    }
169 			}
170 			/* You can see or hear this effect */
171 			if(!mtmp) pline_The("flow reduces to a trickle.");
172 			return;
173 		}
174 #ifdef WIZARD
175 		if (isyou && wizard) {
176 			if (yn("Dry up fountain?") == 'n')
177 				return;
178 		}
179 #endif
180 		/* replace the fountain with ordinary floor */
181 		levl[x][y].typ = ROOM;
182 		levl[x][y].looted = 0;
183 		levl[x][y].blessedftn = 0;
184 		if (cansee(x,y)) pline_The("fountain dries up!");
185 		/* The location is seen if the hero/monster is invisible */
186 		/* or felt if the hero is blind.			 */
187 		newsym(x, y);
188 		level.flags.nfountains--;
189 		if(isyou && in_town(x, y))
190 		    (void) angry_guards(FALSE);
191 	}
192 }
193 
194 void
drinkfountain()195 drinkfountain()
196 {
197 	/* What happens when you drink from a fountain? */
198 	register boolean mgkftn = (levl[u.ux][u.uy].blessedftn == 1);
199 	register int fate = rnd(30);
200 
201 	if (Levitation) {
202 		floating_above("fountain");
203 		return;
204 	}
205 
206 	if (mgkftn && u.uluck >= 0 && fate >= 10) {
207 		int i, ii, littleluck = (u.uluck < 4);
208 
209 		pline("Wow!  This makes you feel great!");
210 		/* blessed restore ability */
211 		for (ii = 0; ii < A_MAX; ii++)
212 		    if (ABASE(ii) < AMAX(ii)) {
213 			ABASE(ii) = AMAX(ii);
214 			flags.botl = 1;
215 		    }
216 		/* gain ability, blessed if "natural" luck is high */
217 		i = rn2(A_MAX);		/* start at a random attribute */
218 		for (ii = 0; ii < A_MAX; ii++) {
219 		    if (adjattrib(i, 1, littleluck ? -1 : 0) && littleluck)
220 			break;
221 		    if (++i >= A_MAX) i = 0;
222 		}
223 		display_nhwindow(WIN_MESSAGE, FALSE);
224 		pline("A wisp of vapor escapes the fountain...");
225 		exercise(A_WIS, TRUE);
226 		levl[u.ux][u.uy].blessedftn = 0;
227 		return;
228 	}
229 
230 	if (fate < 10) {
231 		pline_The("cool draught refreshes you.");
232 		u.uhunger += rnd(10); /* don't choke on water */
233 		newuhs(FALSE);
234 		if(mgkftn) return;
235 	} else {
236 	    switch (fate) {
237 
238 		case 19: /* Self-knowledge */
239 
240 			You_feel("self-knowledgeable...");
241 			display_nhwindow(WIN_MESSAGE, FALSE);
242 			enlightenment(0, TRUE);
243 			exercise(A_WIS, TRUE);
244 			pline_The("feeling subsides.");
245 			break;
246 
247 		case 20: /* Foul water */
248 
249 			pline_The("water is foul!  You gag and vomit.");
250 			morehungry(rn1(20, 11));
251 			vomit();
252 			break;
253 
254 		case 21: /* Poisonous */
255 
256 			pline_The("water is contaminated!");
257 			if (Poison_resistance) {
258 			   pline(
259 			      "Perhaps it is runoff from the nearby %s farm.",
260 				 fruitname(FALSE));
261 			   losehp(rnd(4),"unrefrigerated sip of juice",
262 				KILLED_BY_AN);
263 			   break;
264 			}
265 			losestr(rn1(4,3));
266 			losehp(rnd(10),"contaminated water", KILLED_BY);
267 			exercise(A_CON, FALSE);
268 			break;
269 
270 		case 22: /* Fountain of snakes! */
271 
272 			dowatersnakes();
273 			break;
274 
275 		case 23: /* Water demon */
276 			dowaterdemon();
277 			break;
278 
279 		case 24: /* Curse an item */ {
280 			register struct obj *obj;
281 
282 			pline("This water's no good!");
283 			morehungry(rn1(20, 11));
284 			exercise(A_CON, FALSE);
285 			for(obj = invent; obj ; obj = obj->nobj)
286 				if (!rn2(5))	curse(obj);
287 			break;
288 			}
289 
290 		case 25: /* See invisible */
291 
292 			if (Blind) {
293 			    if (Invisible) {
294 				You("feel transparent.");
295 			    } else {
296 			    	You("feel very self-conscious.");
297 			    	pline("Then it passes.");
298 			    }
299 			} else {
300 			   You("see an image of someone stalking you.");
301 			   pline("But it disappears.");
302 			}
303 			HSee_invisible |= FROMOUTSIDE;
304 			newsym(u.ux,u.uy);
305 			exercise(A_WIS, TRUE);
306 			break;
307 
308 		case 26: /* See Monsters */
309 
310 			(void) monster_detect((struct obj *)0, 0);
311 			exercise(A_WIS, TRUE);
312 			break;
313 
314 		case 27: /* Find a gem in the sparkling waters. */
315 
316 			if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) {
317 				dofindgem();
318 				break;
319 			}
320 
321 		case 28: /* Water Nymph */
322 
323 			dowaternymph();
324 			break;
325 
326 		case 29: /* Scare */ {
327 			register struct monst *mtmp;
328 
329 			pline("This water gives you bad breath!");
330 			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
331 			    if(!DEADMONSTER(mtmp))
332 				monflee(mtmp, 0, FALSE, FALSE);
333 			}
334 			break;
335 
336 		case 30: /* Gushing forth in this room */
337 
338 			dogushforth(TRUE);
339 			break;
340 
341 		default:
342 
343 			pline("This tepid water is tasteless.");
344 			break;
345 	    }
346 	}
347 	dryup(u.ux, u.uy, TRUE);
348 }
349 
350 void
dipfountain(obj)351 dipfountain(obj)
352 register struct obj *obj;
353 {
354 	if (Levitation) {
355 		floating_above("fountain");
356 		return;
357 	}
358 
359 	/* Don't grant Excalibur when there's more than one object.  */
360 	/* (quantity could be > 1 if merged daggers got polymorphed) */
361 	if (obj->otyp == LONG_SWORD && obj->quan == 1L
362 	    && u.ulevel >= 5 && !rn2(6)
363 	    && !obj->oartifact
364 	    && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
365 
366 		if (u.ualign.type != A_LAWFUL) {
367 			/* Ha!  Trying to cheat her. */
368 			pline("A freezing mist rises from the water and envelopes the sword.");
369 			pline_The("fountain disappears!");
370 			curse(obj);
371 			if (obj->spe > -6 && !rn2(3)) obj->spe--;
372 			obj->oerodeproof = FALSE;
373 			exercise(A_WIS, FALSE);
374 		} else {
375 			/* The lady of the lake acts! - Eric Backus */
376 			/* Be *REAL* nice */
377 	  pline("From the murky depths, a hand reaches up to bless the sword.");
378 			pline("As the hand retreats, the fountain disappears!");
379 			obj = oname(obj, artiname(ART_EXCALIBUR));
380 			discover_artifact(ART_EXCALIBUR);
381 			bless(obj);
382 			obj->oeroded = obj->oeroded2 = 0;
383 			obj->oerodeproof = TRUE;
384 			exercise(A_WIS, TRUE);
385 		}
386 		update_inventory();
387 		levl[u.ux][u.uy].typ = ROOM;
388 		levl[u.ux][u.uy].looted = 0;
389 		newsym(u.ux, u.uy);
390 		level.flags.nfountains--;
391 		if(in_town(u.ux, u.uy))
392 		    (void) angry_guards(FALSE);
393 		return;
394 	} else if (get_wet(obj) && !rn2(2))
395 		return;
396 
397 	/* Acid and water don't mix */
398 	if (obj->otyp == POT_ACID) {
399 	    useup(obj);
400 	    return;
401 	}
402 
403 	switch (rnd(30)) {
404 		case 16: /* Curse the item */
405 			curse(obj);
406 			break;
407 		case 17:
408 		case 18:
409 		case 19:
410 		case 20: /* Uncurse the item */
411 			if(obj->cursed) {
412 			    if (!Blind)
413 				pline_The("water glows for a moment.");
414 			    uncurse(obj);
415 			} else {
416 			    pline("A feeling of loss comes over you.");
417 			}
418 			break;
419 		case 21: /* Water Demon */
420 			dowaterdemon();
421 			break;
422 		case 22: /* Water Nymph */
423 			dowaternymph();
424 			break;
425 		case 23: /* an Endless Stream of Snakes */
426 			dowatersnakes();
427 			break;
428 		case 24: /* Find a gem */
429 			if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) {
430 				dofindgem();
431 				break;
432 			}
433 		case 25: /* Water gushes forth */
434 			dogushforth(FALSE);
435 			break;
436 		case 26: /* Strange feeling */
437 			pline("A strange tingling runs up your %s.",
438 							body_part(ARM));
439 			break;
440 		case 27: /* Strange feeling */
441 			You_feel("a sudden chill.");
442 			break;
443 		case 28: /* Strange feeling */
444 			pline("An urge to take a bath overwhelms you.");
445 #ifndef GOLDOBJ
446 			if (u.ugold > 10) {
447 			    u.ugold -= somegold() / 10;
448 			    You("lost some of your gold in the fountain!");
449 			    CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy);
450 			    exercise(A_WIS, FALSE);
451 			}
452 #else
453 			{
454 			    long money = money_cnt(invent);
455 			    struct obj *otmp;
456                             if (money > 10) {
457 				/* Amount to loose.  Might get rounded up as fountains don't pay change... */
458 			        money = somegold(money) / 10;
459 			        for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) {
460 				    int denomination = objects[otmp->otyp].oc_cost;
461 				    long coin_loss = (money + denomination - 1) / denomination;
462                                     coin_loss = min(coin_loss, otmp->quan);
463 				    otmp->quan -= coin_loss;
464 				    money -= coin_loss * denomination;
465 				    if (!otmp->quan) delobj(otmp);
466 				}
467 			        You("lost some of your money in the fountain!");
468 				CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy);
469 			        exercise(A_WIS, FALSE);
470                             }
471 			}
472 #endif
473 			break;
474 		case 29: /* You see coins */
475 
476 		/* We make fountains have more coins the closer you are to the
477 		 * surface.  After all, there will have been more people going
478 		 * by.	Just like a shopping mall!  Chris Woodbury  */
479 
480 		    if (FOUNTAIN_IS_LOOTED(u.ux,u.uy)) break;
481 		    SET_FOUNTAIN_LOOTED(u.ux,u.uy);
482 		    (void) mkgold((long)
483 			(rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5),
484 			u.ux, u.uy);
485 		    if (!Blind)
486 		pline("Far below you, you see coins glistening in the water.");
487 		    exercise(A_WIS, TRUE);
488 		    newsym(u.ux,u.uy);
489 		    break;
490 	}
491 	update_inventory();
492 	dryup(u.ux, u.uy, TRUE);
493 }
494 
495 #ifdef SINKS
496 void
breaksink(x,y)497 breaksink(x,y)
498 int x, y;
499 {
500     if(cansee(x,y) || (x == u.ux && y == u.uy))
501 	pline_The("pipes break!  Water spurts out!");
502     level.flags.nsinks--;
503     levl[x][y].doormask = 0;
504     levl[x][y].typ = FOUNTAIN;
505     level.flags.nfountains++;
506     newsym(x,y);
507 }
508 
509 void
drinksink()510 drinksink()
511 {
512 	struct obj *otmp;
513 	struct monst *mtmp;
514 
515 	if (Levitation) {
516 		floating_above("sink");
517 		return;
518 	}
519 	switch(rn2(20)) {
520 		case 0: You("take a sip of very cold water.");
521 			break;
522 		case 1: You("take a sip of very warm water.");
523 			break;
524 		case 2: You("take a sip of scalding hot water.");
525 			if (Fire_resistance)
526 				pline("It seems quite tasty.");
527 			else losehp(rnd(6), "sipping boiling water", KILLED_BY);
528 			break;
529 		case 3: if (mvitals[PM_SEWER_RAT].mvflags & G_GONE)
530 				pline_The("sink seems quite dirty.");
531 			else {
532 				mtmp = makemon(&mons[PM_SEWER_RAT],
533 						u.ux, u.uy, NO_MM_FLAGS);
534 				if (mtmp) pline("Eek!  There's %s in the sink!",
535 					(Blind || !canspotmon(mtmp)) ?
536 					"something squirmy" :
537 					a_monnam(mtmp));
538 			}
539 			break;
540 		case 4: do {
541 				/* use Luck here instead of u.uluck */
542 				if (!rn2(13) && ((Luck >= 0 && maybe_polyd(is_vampire(youmonst.data), Race_if(PM_VAMPIRE))) ||
543 				    (Luck <= 0 && !maybe_polyd(is_vampire(youmonst.data), Race_if(PM_VAMPIRE))))) {
544 					otmp = mksobj(POT_VAMPIRE_BLOOD,FALSE,FALSE);
545 				} else {
546 					otmp = mkobj(POTION_CLASS,FALSE);
547 					if (otmp->otyp == POT_WATER) {
548 						obfree(otmp, (struct obj *)0);
549 						otmp = (struct obj *) 0;
550 					}
551 				}
552 			} while(!otmp);
553 			if (rnf(1,Luck+17)) otmp->cursed = 1;
554 			else if (rnf(1,17-Luck)) otmp->blessed = 1;
555 			else otmp->cursed = otmp->blessed = 0;
556 			pline("Some %s liquid flows from the faucet.",
557 			      Blind ? "odd" :
558 			      hcolor(OBJ_DESCR(objects[otmp->otyp])));
559 			otmp->dknown = !(Blind || Hallucination);
560 			otmp->quan++; /* Avoid panic upon useup() */
561 			otmp->fromsink = 1; /* kludge for docall() */
562 			(void) dopotion(otmp);
563 			obfree(otmp, (struct obj *)0);
564 			break;
565 		case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) {
566 			    You("find a ring in the sink!");
567 			    (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE);
568 			    levl[u.ux][u.uy].looted |= S_LRING;
569 			    exercise(A_WIS, TRUE);
570 			    newsym(u.ux,u.uy);
571 			} else pline("Some dirty water backs up in the drain.");
572 			break;
573 		case 6: breaksink(u.ux,u.uy);
574 			break;
575 		case 7: pline_The("water moves as though of its own will!");
576 			if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
577 			    || !makemon(&mons[PM_WATER_ELEMENTAL],
578 					u.ux, u.uy, NO_MM_FLAGS))
579 				pline("But it quiets down.");
580 			break;
581 		case 8: pline("Yuk, this water tastes awful.");
582 			more_experienced(1,1,0);
583 			newexplevel();
584 			break;
585 		case 9: pline("Gaggg... this tastes like sewage!  You vomit.");
586 			morehungry(rn1(30-ACURR(A_CON), 11));
587 			vomit();
588 			break;
589 		case 10: pline("This water contains toxic wastes!");
590 			if (!Unchanging) {
591 				You("undergo a freakish metamorphosis!");
592 				polyself(FALSE);
593 			}
594 			break;
595 		/* more odd messages --JJB */
596 		case 11: You_hear("clanking from the pipes...");
597 			break;
598 		case 12: You_hear("snatches of song from among the sewers...");
599 			break;
600 		case 19: if (Hallucination) {
601 		   pline("From the murky drain, a hand reaches up... --oops--");
602 				break;
603 			}
604 		default: You("take a sip of %s water.",
605 			rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot");
606 	}
607 }
608 #endif /* SINKS */
609 
610 /*fountain.c*/
611