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