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
9STATIC_DCL void NDECL(dowatersnakes);
10STATIC_DCL void NDECL(dowaterdemon);
11STATIC_DCL void NDECL(dowaternymph);
12STATIC_PTR void FDECL(gush, (int,int,genericptr_t));
13STATIC_DCL void NDECL(dofindgem);
14
15void
16floating_above(what)
17const char *what;
18{
19    You("are floating high above the %s.", what);
20}
21
22STATIC_OVL void
23dowatersnakes() /* 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
42STATIC_OVL
43void
44dowaterdemon() /* 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();
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
68STATIC_OVL void
69dowaternymph() /* 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
89void
90dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */
91int 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
104STATIC_PTR void
105gush(x, y, poolcnt)
106int x, y;
107genericptr_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
136STATIC_OVL void
137dofindgem() /* 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
148void
149dryup(x, y, isyou)
150xchar x, y;
151boolean 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
194void
195drinkfountain()
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);
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
350void
351dipfountain(obj)
352register 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
496void
497breaksink(x,y)
498int 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
509void
510drinksink()
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				otmp = mkobj(POTION_CLASS,FALSE);
542				if (otmp->otyp == POT_WATER) {
543					obfree(otmp, (struct obj *)0);
544					otmp = (struct obj *) 0;
545				}
546			} while(!otmp);
547			otmp->cursed = otmp->blessed = 0;
548			pline("Some %s liquid flows from the faucet.",
549			      Blind ? "odd" :
550			      hcolor(OBJ_DESCR(objects[otmp->otyp])));
551			otmp->dknown = !(Blind || Hallucination);
552			otmp->quan++; /* Avoid panic upon useup() */
553			otmp->fromsink = 1; /* kludge for docall() */
554			(void) dopotion(otmp);
555			obfree(otmp, (struct obj *)0);
556			break;
557		case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) {
558			    You("find a ring in the sink!");
559			    (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE);
560			    levl[u.ux][u.uy].looted |= S_LRING;
561			    exercise(A_WIS, TRUE);
562			    newsym(u.ux,u.uy);
563			} else pline("Some dirty water backs up in the drain.");
564			break;
565		case 6: breaksink(u.ux,u.uy);
566			break;
567		case 7: pline_The("water moves as though of its own will!");
568			if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
569			    || !makemon(&mons[PM_WATER_ELEMENTAL],
570					u.ux, u.uy, NO_MM_FLAGS))
571				pline("But it quiets down.");
572			break;
573		case 8: pline("Yuk, this water tastes awful.");
574			more_experienced(1,0);
575			newexplevel();
576			break;
577		case 9: pline("Gaggg... this tastes like sewage!  You vomit.");
578			morehungry(rn1(30-ACURR(A_CON), 11));
579			vomit();
580			break;
581		case 10: pline("This water contains toxic wastes!");
582			if (!Unchanging) {
583				You("undergo a freakish metamorphosis!");
584				polyself(FALSE);
585			}
586			break;
587		/* more odd messages --JJB */
588		case 11: You_hear("clanking from the pipes...");
589			break;
590		case 12: You_hear("snatches of song from among the sewers...");
591			break;
592		case 19: if (Hallucination) {
593		   pline("From the murky drain, a hand reaches up... --oops--");
594				break;
595			}
596		default: You("take a sip of %s water.",
597			rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot");
598	}
599}
600#endif /* SINKS */
601
602/*fountain.c*/
603