dumplog message history groundwork
[aNetHack.git] / src / fountain.c
blobc020c394b0948f8ee6b06268ab3cd60fe1b41a4b
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 %s gives you bad breath!",
341 hliquid("water"));
342 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
343 if (DEADMONSTER(mtmp))
344 continue;
345 monflee(mtmp, 0, FALSE, FALSE);
347 break;
349 case 30: /* Gushing forth in this room */
350 dogushforth(TRUE);
351 break;
352 default:
353 pline("This tepid %s is tasteless.",
354 hliquid("water"));
355 break;
358 dryup(u.ux, u.uy, TRUE);
361 void
362 dipfountain(obj)
363 register struct obj *obj;
365 if (Levitation) {
366 floating_above("fountain");
367 return;
370 /* Don't grant Excalibur when there's more than one object. */
371 /* (quantity could be > 1 if merged daggers got polymorphed) */
372 if (obj->otyp == LONG_SWORD && obj->quan == 1L && u.ulevel >= 5 && !rn2(6)
373 && !obj->oartifact
374 && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
375 if (u.ualign.type != A_LAWFUL) {
376 /* Ha! Trying to cheat her. */
377 pline("A freezing mist rises from the %s and envelopes the sword.",
378 hliquid("water"));
379 pline_The("fountain disappears!");
380 curse(obj);
381 if (obj->spe > -6 && !rn2(3))
382 obj->spe--;
383 obj->oerodeproof = FALSE;
384 exercise(A_WIS, FALSE);
385 } else {
386 /* The lady of the lake acts! - Eric Backus */
387 /* Be *REAL* nice */
388 pline(
389 "From the murky depths, a hand reaches up to bless the sword.");
390 pline("As the hand retreats, the fountain disappears!");
391 obj = oname(obj, artiname(ART_EXCALIBUR));
392 discover_artifact(ART_EXCALIBUR);
393 bless(obj);
394 obj->oeroded = obj->oeroded2 = 0;
395 obj->oerodeproof = TRUE;
396 exercise(A_WIS, TRUE);
398 update_inventory();
399 levl[u.ux][u.uy].typ = ROOM;
400 levl[u.ux][u.uy].looted = 0;
401 newsym(u.ux, u.uy);
402 level.flags.nfountains--;
403 if (in_town(u.ux, u.uy))
404 (void) angry_guards(FALSE);
405 return;
406 } else {
407 int er = water_damage(obj, NULL, TRUE);
409 if (obj->otyp == POT_ACID
410 && er != ER_DESTROYED) { /* Acid and water don't mix */
411 useup(obj);
412 return;
413 } else if (er != ER_NOTHING && !rn2(2)) { /* no further effect */
414 return;
418 switch (rnd(30)) {
419 case 16: /* Curse the item */
420 curse(obj);
421 break;
422 case 17:
423 case 18:
424 case 19:
425 case 20: /* Uncurse the item */
426 if (obj->cursed) {
427 if (!Blind)
428 pline_The("%s glows for a moment.", hliquid("water"));
429 uncurse(obj);
430 } else {
431 pline("A feeling of loss comes over you.");
433 break;
434 case 21: /* Water Demon */
435 dowaterdemon();
436 break;
437 case 22: /* Water Nymph */
438 dowaternymph();
439 break;
440 case 23: /* an Endless Stream of Snakes */
441 dowatersnakes();
442 break;
443 case 24: /* Find a gem */
444 if (!FOUNTAIN_IS_LOOTED(u.ux, u.uy)) {
445 dofindgem();
446 break;
448 case 25: /* Water gushes forth */
449 dogushforth(FALSE);
450 break;
451 case 26: /* Strange feeling */
452 pline("A strange tingling runs up your %s.", body_part(ARM));
453 break;
454 case 27: /* Strange feeling */
455 You_feel("a sudden chill.");
456 break;
457 case 28: /* Strange feeling */
458 pline("An urge to take a bath overwhelms you.");
460 long money = money_cnt(invent);
461 struct obj *otmp;
462 if (money > 10) {
463 /* Amount to lose. Might get rounded up as fountains don't
464 * pay change... */
465 money = somegold(money) / 10;
466 for (otmp = invent; otmp && money > 0; otmp = otmp->nobj)
467 if (otmp->oclass == COIN_CLASS) {
468 int denomination = objects[otmp->otyp].oc_cost;
469 long coin_loss =
470 (money + denomination - 1) / denomination;
471 coin_loss = min(coin_loss, otmp->quan);
472 otmp->quan -= coin_loss;
473 money -= coin_loss * denomination;
474 if (!otmp->quan)
475 delobj(otmp);
477 You("lost some of your money in the fountain!");
478 CLEAR_FOUNTAIN_LOOTED(u.ux, u.uy);
479 exercise(A_WIS, FALSE);
482 break;
483 case 29: /* You see coins */
484 /* We make fountains have more coins the closer you are to the
485 * surface. After all, there will have been more people going
486 * by. Just like a shopping mall! Chris Woodbury */
488 if (FOUNTAIN_IS_LOOTED(u.ux, u.uy))
489 break;
490 SET_FOUNTAIN_LOOTED(u.ux, u.uy);
491 (void) mkgold((long) (rnd((dunlevs_in_dungeon(&u.uz) - dunlev(&u.uz)
492 + 1) * 2) + 5),
493 u.ux, u.uy);
494 if (!Blind)
495 pline("Far below you, you see coins glistening in the %s.",
496 hliquid("water"));
497 exercise(A_WIS, TRUE);
498 newsym(u.ux, u.uy);
499 break;
501 update_inventory();
502 dryup(u.ux, u.uy, TRUE);
505 void
506 breaksink(x, y)
507 int x, y;
509 if (cansee(x, y) || (x == u.ux && y == u.uy))
510 pline_The("pipes break! Water spurts out!");
511 level.flags.nsinks--;
512 levl[x][y].doormask = 0;
513 levl[x][y].typ = FOUNTAIN;
514 level.flags.nfountains++;
515 newsym(x, y);
518 void
519 drinksink()
521 struct obj *otmp;
522 struct monst *mtmp;
524 if (Levitation) {
525 floating_above("sink");
526 return;
528 switch (rn2(20)) {
529 case 0:
530 You("take a sip of very cold %s.", hliquid("water"));
531 break;
532 case 1:
533 You("take a sip of very warm %s.", hliquid("water"));
534 break;
535 case 2:
536 You("take a sip of scalding hot %s.", hliquid("water"));
537 if (Fire_resistance)
538 pline("It seems quite tasty.");
539 else
540 losehp(rnd(6), "sipping boiling water", KILLED_BY);
541 /* boiling water burns considered fire damage */
542 break;
543 case 3:
544 if (mvitals[PM_SEWER_RAT].mvflags & G_GONE)
545 pline_The("sink seems quite dirty.");
546 else {
547 mtmp = makemon(&mons[PM_SEWER_RAT], u.ux, u.uy, NO_MM_FLAGS);
548 if (mtmp)
549 pline("Eek! There's %s in the sink!",
550 (Blind || !canspotmon(mtmp)) ? "something squirmy"
551 : a_monnam(mtmp));
553 break;
554 case 4:
555 do {
556 otmp = mkobj(POTION_CLASS, FALSE);
557 if (otmp->otyp == POT_WATER) {
558 obfree(otmp, (struct obj *) 0);
559 otmp = (struct obj *) 0;
561 } while (!otmp);
562 otmp->cursed = otmp->blessed = 0;
563 pline("Some %s liquid flows from the faucet.",
564 Blind ? "odd" : hcolor(OBJ_DESCR(objects[otmp->otyp])));
565 otmp->dknown = !(Blind || Hallucination);
566 otmp->quan++; /* Avoid panic upon useup() */
567 otmp->fromsink = 1; /* kludge for docall() */
568 (void) dopotion(otmp);
569 obfree(otmp, (struct obj *) 0);
570 break;
571 case 5:
572 if (!(levl[u.ux][u.uy].looted & S_LRING)) {
573 You("find a ring in the sink!");
574 (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE);
575 levl[u.ux][u.uy].looted |= S_LRING;
576 exercise(A_WIS, TRUE);
577 newsym(u.ux, u.uy);
578 } else
579 pline("Some dirty %s backs up in the drain.", hliquid("water"));
580 break;
581 case 6:
582 breaksink(u.ux, u.uy);
583 break;
584 case 7:
585 pline_The("%s moves as though of its own will!", hliquid("water"));
586 if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
587 || !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, NO_MM_FLAGS))
588 pline("But it quiets down.");
589 break;
590 case 8:
591 pline("Yuk, this %s tastes awful.", hliquid("water"));
592 more_experienced(1, 0);
593 newexplevel();
594 break;
595 case 9:
596 pline("Gaggg... this tastes like sewage! You vomit.");
597 morehungry(rn1(30 - ACURR(A_CON), 11));
598 vomit();
599 break;
600 case 10:
601 pline("This %s contains toxic wastes!", hliquid("water"));
602 if (!Unchanging) {
603 You("undergo a freakish metamorphosis!");
604 polyself(0);
606 break;
607 /* more odd messages --JJB */
608 case 11:
609 You_hear("clanking from the pipes...");
610 break;
611 case 12:
612 You_hear("snatches of song from among the sewers...");
613 break;
614 case 19:
615 if (Hallucination) {
616 pline("From the murky drain, a hand reaches up... --oops--");
617 break;
619 default:
620 You("take a sip of %s %s.",
621 rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot",
622 hliquid("water"));
626 /*fountain.c*/