/* SCCS Id: @(#)fountain.c 3.3 1999/08/16 */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* NetHack may be freely redistributed. See license for details. */ /* Code for drinking from fountains. */ #include "hack.h" STATIC_DCL void NDECL(dowatersnakes); STATIC_DCL void NDECL(dowaterdemon); STATIC_DCL void NDECL(dowaternymph); STATIC_PTR void FDECL(gush, (int,int,genericptr_t)); STATIC_DCL void NDECL(dofindgem); void floating_above(what) const char *what; { You("are floating high above the %s.", what); } STATIC_OVL void dowatersnakes() /* Fountain of snakes! */ { register int num = rn1(5,2); struct monst *mtmp; if (!(mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) { if (!Blind) pline("An endless stream of %s pours forth!", Hallucination ? makeplural(rndmonnam()) : "snakes"); else You_hear("%s hissing!", something); while(num-- > 0) if((mtmp = makemon(&mons[PM_WATER_MOCCASIN], u.ux, u.uy, NO_MM_FLAGS)) && t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } else pline_The("fountain bubbles furiously for a moment, then calms."); } STATIC_OVL void dowaterdemon() /* Water demon */ { register struct monst *mtmp; if(mvitals[PM_WATER_DEMON].mvflags & G_GONE) return; if((mtmp = makemon(&mons[PM_WATER_DEMON],u.ux,u.uy, NO_MM_FLAGS))) { if (!Blind) You("unleash %s!", a_monnam(mtmp)); else You_feel("the presence of evil."); /* Give those on low levels a (slightly) better chance of survival */ if (rnd(100) > (80 + level_difficulty())) { pline("Grateful for %s release, %s grants you a wish!", his[pronoun_gender(mtmp)], he[pronoun_gender(mtmp)]); makewish(); mongone(mtmp); } else if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } } STATIC_OVL void dowaternymph() /* Water Nymph */ { register struct monst *mtmp; if(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) return; if((mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) { if (!Blind) You("attract %s!", a_monnam(mtmp)); else You_hear("a seductive voice."); mtmp->msleeping = 0; if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } else if (!Blind) pline("A large bubble rises to the surface and pops."); else You_hear("a loud pop."); } void dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */ int drinking; { int madepool = 0; do_clear_area(u.ux, u.uy, 7, gush, (genericptr_t)&madepool); if (!madepool) { if (drinking) Your("thirst is quenched."); else pline("Water sprays all over you."); } } STATIC_PTR void gush(x, y, poolcnt) int x, y; genericptr_t poolcnt; { register struct monst *mtmp; register struct trap *ttmp; if (((x+y)%2) || (x == u.ux && y == u.uy) || (rn2(1 + distmin(u.ux, u.uy, x, y))) || (levl[x][y].typ != ROOM) || (sobj_at(BOULDER, x, y)) || nexttodoor(x, y)) return; if ((ttmp = t_at(x, y)) != 0 && !delfloortrap(ttmp)) return; if (!((*(int *)poolcnt)++)) pline("Water gushes forth from the overflowing fountain!"); /* Put a pool at x, y */ levl[x][y].typ = POOL; /* No kelp! */ del_engr_at(x, y); water_damage(level.objects[x][y], FALSE, TRUE); if ((mtmp = m_at(x, y)) != 0) (void) minwater(mtmp); else newsym(x,y); } STATIC_OVL void dofindgem() /* Find a gem in the sparkling waters. */ { if (!Blind) You("spot a gem in the sparkling waters!"); (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1), u.ux, u.uy, FALSE); levl[u.ux][u.uy].looted |= F_LOOTED; newsym(u.ux, u.uy); exercise(A_WIS, TRUE); /* a discovery! */ } void dryup(x, y, isyou) xchar x, y; boolean isyou; { if (IS_FOUNTAIN(levl[x][y].typ) && (!rn2(3) || (levl[x][y].looted & F_WARNED))) { s_level *slev = Is_special(&u.uz); if(isyou && slev && slev->flags.town && !(levl[x][y].looted & F_WARNED)) { struct monst *mtmp; levl[x][y].looted |= F_WARNED; /* Warn about future fountain use. */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { pline("%s yells:", Amonnam(mtmp)); verbalize("Hey, stop using that fountain!"); break; } } /* You can see or hear this effect */ if(!mtmp) pline_The("flow reduces to a trickle."); return; } #ifdef WIZARD if (isyou && wizard) { if (yn("Dry up fountain?") == 'n') return; } #endif if (cansee(x,y)) pline_The("fountain dries up!"); levl[x][y].typ = ROOM; levl[x][y].looted = 0; levl[x][y].blessedftn = 0; /* The location is seen if the hero/monster is invisible */ /* or felt if the hero is blind. */ newsym(x, y); level.flags.nfountains--; if(isyou && slev && slev->flags.town) (void) angry_guards(FALSE); } } void drinkfountain() { /* What happens when you drink from a fountain? */ register boolean mgkftn = (levl[u.ux][u.uy].blessedftn == 1); register int fate = rnd(30); if (Levitation) { floating_above("fountain"); return; } if (mgkftn && u.uluck >= 0 && fate >= 10) { int i, ii, littleluck = (u.uluck < 4); pline("Wow! This makes you feel great!"); /* blessed restore ability */ for (ii = 0; ii < A_MAX; ii++) if (ABASE(ii) < AMAX(ii)) { ABASE(ii) = AMAX(ii); flags.botl = 1; } /* gain ability, blessed if "natural" luck is high */ i = rn2(A_MAX); /* start at a random attribute */ for (ii = 0; ii < A_MAX; ii++) { if (adjattrib(i, 1, littleluck ? -1 : 0) && littleluck) break; if (++i >= A_MAX) i = 0; } display_nhwindow(WIN_MESSAGE, FALSE); pline("A wisp of vapor escapes the fountain..."); exercise(A_WIS, TRUE); levl[u.ux][u.uy].blessedftn = 0; return; } if (fate < 10) { pline_The("cool draught refreshes you."); u.uhunger += rnd(10); /* don't choke on water */ newuhs(FALSE); if(mgkftn) return; } else { switch (fate) { case 19: /* Self-knowledge */ You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(0); exercise(A_WIS, TRUE); pline_The("feeling subsides."); break; case 20: /* Foul water */ pline_The("water is foul! You gag and vomit."); morehungry(rn1(20, 11)); vomit(); break; case 21: /* Poisonous */ pline_The("water is contaminated!"); if (Poison_resistance) { pline("Perhaps it is runoff from the nearby %s farm.", pl_fruit); losehp(rnd(4),"unrefrigerated sip of juice", KILLED_BY_AN); break; } losestr(rn1(4,3)); losehp(rnd(10),"contaminated water", KILLED_BY); exercise(A_CON, FALSE); break; case 22: /* Fountain of snakes! */ dowatersnakes(); break; case 23: /* Water demon */ dowaterdemon(); break; case 24: /* Curse an item */ { register struct obj *obj; pline("This water's no good!"); morehungry(rn1(20, 11)); exercise(A_CON, FALSE); for(obj = invent; obj ; obj = obj->nobj) if (!rn2(5)) curse(obj); break; } case 25: /* See invisible */ if (Blind) { if (Invisible) { You("feel very self-conscious."); pline("Then it passes."); } else { You("feel transparent."); } } else { You("see an image of someone stalking you."); pline("But it disappears."); } HSee_invisible |= FROMOUTSIDE; newsym(u.ux,u.uy); exercise(A_WIS, TRUE); break; case 26: /* See Monsters */ (void) monster_detect((struct obj *)0, 0); exercise(A_WIS, TRUE); break; case 27: /* Find a gem in the sparkling waters. */ if (!levl[u.ux][u.uy].looted) { dofindgem(); break; } case 28: /* Water Nymph */ dowaternymph(); break; case 29: /* Scare */ { register struct monst *mtmp; pline("This water gives you bad breath!"); for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(!DEADMONSTER(mtmp)) mtmp->mflee = 1; } break; case 30: /* Gushing forth in this room */ dogushforth(TRUE); break; default: pline("This tepid water is tasteless."); break; } } dryup(u.ux, u.uy, TRUE); } void dipfountain(obj) register struct obj *obj; { if (Levitation) { floating_above("fountain"); return; } /* Don't grant Excalibur when there's more than one object. */ /* (quantity could be > 1 if merged daggers got polymorphed) */ if (obj->otyp == LONG_SWORD && obj->quan == 1L && u.ulevel >= 5 && !rn2(6) && !obj->oartifact && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) { s_level *slev = Is_special(&u.uz); if (u.ualign.type != A_LAWFUL) { /* Ha! Trying to cheat her. */ pline("A freezing mist rises from the water and envelopes the sword."); pline_The("fountain disappears!"); curse(obj); if (obj->spe > -6 && !rn2(3)) obj->spe--; obj->oerodeproof = FALSE; exercise(A_WIS, FALSE); } else { /* The lady of the lake acts! - Eric Backus */ /* Be *REAL* nice */ pline("From the murky depths, a hand reaches up to bless the sword."); pline("As the hand retreats, the fountain disappears!"); obj = oname(obj, artiname(ART_EXCALIBUR)); discover_artifact(ART_EXCALIBUR); bless(obj); obj->oeroded = obj->oeroded2 = 0; obj->oerodeproof = TRUE; exercise(A_WIS, TRUE); } levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].looted = 0; if(Invisible) newsym(u.ux, u.uy); level.flags.nfountains--; if(slev && slev->flags.town) (void) angry_guards(FALSE); return; } else (void) get_wet(obj); /* Acid and water don't mix */ if (obj->otyp == POT_ACID) { useup(obj); return; } switch (rnd(30)) { case 16: /* Curse the item */ curse(obj); break; case 17: case 18: case 19: case 20: /* Uncurse the item */ if(obj->cursed) { if (!Blind) pline_The("water glows for a moment."); uncurse(obj); } else { pline("A feeling of loss comes over you."); } break; case 21: /* Water Demon */ dowaterdemon(); break; case 22: /* Water Nymph */ dowaternymph(); break; case 23: /* an Endless Stream of Snakes */ dowatersnakes(); break; case 24: /* Find a gem */ if (!levl[u.ux][u.uy].looted) { dofindgem(); break; } case 25: /* Water gushes forth */ dogushforth(FALSE); break; case 26: /* Strange feeling */ pline("A strange tingling runs up your %s.", body_part(ARM)); break; case 27: /* Strange feeling */ You_feel("a sudden chill."); break; case 28: /* Strange feeling */ pline("An urge to take a bath overwhelms you."); if (u.ugold > 10) { u.ugold -= somegold() / 10; You("lost some of your gold in the fountain!"); levl[u.ux][u.uy].looted &= ~F_LOOTED; exercise(A_WIS, FALSE); } break; case 29: /* You see coins */ /* We make fountains have more coins the closer you are to the * surface. After all, there will have been more people going * by. Just like a shopping mall! Chris Woodbury */ if (levl[u.ux][u.uy].looted) break; levl[u.ux][u.uy].looted |= F_LOOTED; (void) mkgold((long) (rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5), u.ux, u.uy); if (!Blind) pline("Far below you, you see coins glistening in the water."); exercise(A_WIS, TRUE); newsym(u.ux,u.uy); break; } dryup(u.ux, u.uy, TRUE); } #ifdef SINKS void breaksink(x,y) int x, y; { if(cansee(x,y) || (x == u.ux && y == u.uy)) pline_The("pipes break! Water spurts out!"); level.flags.nsinks--; levl[x][y].doormask = 0; levl[x][y].typ = FOUNTAIN; level.flags.nfountains++; newsym(x,y); } void drinksink() { struct obj *otmp; struct monst *mtmp; if (Levitation) { floating_above("sink"); return; } switch(rn2(20)) { case 0: You("take a sip of very cold water."); break; case 1: You("take a sip of very warm water."); break; case 2: You("take a sip of scalding hot water."); if (Fire_resistance) pline("It seems quite tasty."); else losehp(rnd(6), "sipping boiling water", KILLED_BY); break; case 3: if (mvitals[PM_SEWER_RAT].mvflags & G_GONE) pline_The("sink seems quite dirty."); else { mtmp = makemon(&mons[PM_SEWER_RAT], u.ux, u.uy, NO_MM_FLAGS); pline("Eek! There's %s in the sink!", Blind ? "something squirmy" : a_monnam(mtmp)); } break; case 4: do { otmp = mkobj(POTION_CLASS,FALSE); if (otmp->otyp == POT_WATER) { obfree(otmp, (struct obj *)0); otmp = (struct obj *) 0; } } while(!otmp); otmp->cursed = otmp->blessed = 0; pline("Some %s liquid flows from the faucet.", Blind ? "odd" : hcolor(OBJ_DESCR(objects[otmp->otyp]))); otmp->dknown = !(Blind || Hallucination); otmp->quan++; /* Avoid panic upon useup() */ otmp->corpsenm = 1; /* kludge for docall() */ (void) dopotion(otmp); obfree(otmp, (struct obj *)0); break; case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) { You("find a ring in the sink!"); (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE); levl[u.ux][u.uy].looted |= S_LRING; exercise(A_WIS, TRUE); newsym(u.ux,u.uy); } else pline("Some dirty water backs up in the drain."); break; case 6: breaksink(u.ux,u.uy); break; case 7: pline_The("water moves as though of its own will!"); if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE) || !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, NO_MM_FLAGS)) pline("But it quiets down."); break; case 8: pline("Yuk, this water tastes awful."); more_experienced(1,0); newexplevel(); break; case 9: pline("Gaggg... this tastes like sewage! You vomit."); morehungry(rn1(30-ACURR(A_CON), 11)); vomit(); break; case 10: pline("This water contains toxic wastes!"); if (!Unchanging) { You("undergo a freakish metamorphosis!"); polyself(); } break; /* more odd messages --JJB */ case 11: You_hear("clanking from the pipes..."); break; case 12: You_hear("snatches of song from among the sewers..."); break; case 19: if (Hallucination) { pline("From the murky drain, a hand reaches up... --oops--"); break; } default: You("take a sip of %s water.", rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot"); } } #endif /* SINKS */ /*fountain.c*/