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