1 | /* SCCS Id: @(#)fountain.c 3.3 1999/08/16 */ 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 | 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); 14 | 15 | void 16 | floating_above(what) 17 | const char *what; 18 | { 19 | You("are floating high above the %s.", what); 20 | } 21 | 22 | STATIC_OVL void 23 | dowatersnakes() /* 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 | 42 | STATIC_OVL 43 | void 44 | dowaterdemon() /* Water demon */ 45 | { 46 | register struct monst *mtmp; 47 | 48 | if(mvitals[PM_WATER_DEMON].mvflags & G_GONE) return; 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 | his[pronoun_gender(mtmp)], he[pronoun_gender(mtmp)]); 59 | makewish(); 60 | mongone(mtmp); 61 | } else if (t_at(mtmp->mx, mtmp->my)) 62 | (void) mintrap(mtmp); 63 | } 64 | } 65 | 66 | STATIC_OVL void 67 | dowaternymph() /* Water Nymph */ 68 | { 69 | register struct monst *mtmp; 70 | 71 | if(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) return; 72 | if((mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) { 73 | if (!Blind) 74 | You("attract %s!", a_monnam(mtmp)); 75 | else 76 | You_hear("a seductive voice."); 77 | mtmp->msleeping = 0; 78 | if (t_at(mtmp->mx, mtmp->my)) 79 | (void) mintrap(mtmp); 80 | } else 81 | if (!Blind) 82 | pline("A large bubble rises to the surface and pops."); 83 | else 84 | You_hear("a loud pop."); 85 | } 86 | 87 | void 88 | dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */ 89 | int drinking; 90 | { 91 | int madepool = 0; 92 | 93 | do_clear_area(u.ux, u.uy, 7, gush, (genericptr_t)&madepool); 94 | if (!madepool) { 95 | if (drinking) 96 | Your("thirst is quenched."); 97 | else 98 | pline("Water sprays all over you."); 99 | } 100 | } 101 | 102 | STATIC_PTR void 103 | gush(x, y, poolcnt) 104 | int x, y; 105 | genericptr_t poolcnt; 106 | { 107 | register struct monst *mtmp; 108 | register struct trap *ttmp; 109 | 110 | if (((x+y)%2) || (x == u.ux && y == u.uy) || 111 | (rn2(1 + distmin(u.ux, u.uy, x, y))) || 112 | (levl[x][y].typ != ROOM) || 113 | (sobj_at(BOULDER, x, y)) || nexttodoor(x, y)) 114 | return; 115 | 116 | if ((ttmp = t_at(x, y)) != 0 && !delfloortrap(ttmp)) 117 | return; 118 | 119 | if (!((*(int *)poolcnt)++)) 120 | pline("Water gushes forth from the overflowing fountain!"); 121 | 122 | /* Put a pool at x, y */ 123 | levl[x][y].typ = POOL; 124 | /* No kelp! */ 125 | del_engr_at(x, y); 126 | water_damage(level.objects[x][y], FALSE, TRUE); 127 | 128 | if ((mtmp = m_at(x, y)) != 0) 129 | (void) minwater(mtmp); 130 | else 131 | newsym(x,y); 132 | } 133 | 134 | STATIC_OVL void 135 | dofindgem() /* Find a gem in the sparkling waters. */ 136 | { 137 | if (!Blind) You("spot a gem in the sparkling waters!"); 138 | (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1), 139 | u.ux, u.uy, FALSE); 140 | levl[u.ux][u.uy].looted |= F_LOOTED; 141 | newsym(u.ux, u.uy); 142 | exercise(A_WIS, TRUE); /* a discovery! */ 143 | } 144 | 145 | void 146 | dryup(x, y, isyou) 147 | xchar x, y; 148 | boolean isyou; 149 | { 150 | if (IS_FOUNTAIN(levl[x][y].typ) && 151 | (!rn2(3) || (levl[x][y].looted & F_WARNED))) { 152 | s_level *slev = Is_special(&u.uz); 153 | if(isyou && slev && slev->flags.town && 154 | !(levl[x][y].looted & F_WARNED)) { 155 | struct monst *mtmp; 156 | levl[x][y].looted |= F_WARNED; 157 | /* Warn about future fountain use. */ 158 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 159 | if (DEADMONSTER(mtmp)) continue; 160 | if ((mtmp->data == &mons[PM_WATCHMAN] || 161 | mtmp->data == &mons[PM_WATCH_CAPTAIN]) && 162 | couldsee(mtmp->mx, mtmp->my) && 163 | mtmp->mpeaceful) { 164 | pline("%s yells:", Amonnam(mtmp)); 165 | verbalize("Hey, stop using that fountain!"); 166 | break; 167 | } 168 | } 169 | /* You can see or hear this effect */ 170 | if(!mtmp) pline_The("flow reduces to a trickle."); 171 | return; 172 | } 173 | #ifdef WIZARD 174 | if (isyou && wizard) { 175 | if (yn("Dry up fountain?") == 'n') 176 | return; 177 | } 178 | #endif 179 | if (cansee(x,y)) pline_The("fountain dries up!"); 180 | levl[x][y].typ = ROOM; 181 | levl[x][y].looted = 0; 182 | levl[x][y].blessedftn = 0; 183 | /* The location is seen if the hero/monster is invisible */ 184 | /* or felt if the hero is blind. */ 185 | newsym(x, y); 186 | level.flags.nfountains--; 187 | if(isyou && slev && slev->flags.town) 188 | (void) angry_guards(FALSE); 189 | } 190 | } 191 | 192 | void 193 | drinkfountain() 194 | { 195 | /* What happens when you drink from a fountain? */ 196 | register boolean mgkftn = (levl[u.ux][u.uy].blessedftn == 1); 197 | register int fate = rnd(30); 198 | 199 | if (Levitation) { 200 | floating_above("fountain"); 201 | return; 202 | } 203 | 204 | if (mgkftn && u.uluck >= 0 && fate >= 10) { 205 | int i, ii, littleluck = (u.uluck < 4); 206 | 207 | pline("Wow! This makes you feel great!"); 208 | /* blessed restore ability */ 209 | for (ii = 0; ii < A_MAX; ii++) 210 | if (ABASE(ii) < AMAX(ii)) { 211 | ABASE(ii) = AMAX(ii); 212 | flags.botl = 1; 213 | } 214 | /* gain ability, blessed if "natural" luck is high */ 215 | i = rn2(A_MAX); /* start at a random attribute */ 216 | for (ii = 0; ii < A_MAX; ii++) { 217 | if (adjattrib(i, 1, littleluck ? -1 : 0) && littleluck) 218 | break; 219 | if (++i >= A_MAX) i = 0; 220 | } 221 | display_nhwindow(WIN_MESSAGE, FALSE); 222 | pline("A wisp of vapor escapes the fountain..."); 223 | exercise(A_WIS, TRUE); 224 | levl[u.ux][u.uy].blessedftn = 0; 225 | return; 226 | } 227 | 228 | if (fate < 10) { 229 | pline_The("cool draught refreshes you."); 230 | u.uhunger += rnd(10); /* don't choke on water */ 231 | newuhs(FALSE); 232 | if(mgkftn) return; 233 | } else { 234 | switch (fate) { 235 | 236 | case 19: /* Self-knowledge */ 237 | 238 | You_feel("self-knowledgeable..."); 239 | display_nhwindow(WIN_MESSAGE, FALSE); 240 | enlightenment(0); 241 | exercise(A_WIS, TRUE); 242 | pline_The("feeling subsides."); 243 | break; 244 | 245 | case 20: /* Foul water */ 246 | 247 | pline_The("water is foul! You gag and vomit."); 248 | morehungry(rn1(20, 11)); 249 | vomit(); 250 | break; 251 | 252 | case 21: /* Poisonous */ 253 | 254 | pline_The("water is contaminated!"); 255 | if (Poison_resistance) { 256 | pline("Perhaps it is runoff from the nearby %s farm.", pl_fruit); 257 | losehp(rnd(4),"unrefrigerated sip of juice", 258 | KILLED_BY_AN); 259 | break; 260 | } 261 | losestr(rn1(4,3)); 262 | losehp(rnd(10),"contaminated water", KILLED_BY); 263 | exercise(A_CON, FALSE); 264 | break; 265 | 266 | case 22: /* Fountain of snakes! */ 267 | 268 | dowatersnakes(); 269 | break; 270 | 271 | case 23: /* Water demon */ 272 | dowaterdemon(); 273 | break; 274 | 275 | case 24: /* Curse an item */ { 276 | register struct obj *obj; 277 | 278 | pline("This water's no good!"); 279 | morehungry(rn1(20, 11)); 280 | exercise(A_CON, FALSE); 281 | for(obj = invent; obj ; obj = obj->nobj) 282 | if (!rn2(5)) curse(obj); 283 | break; 284 | } 285 | 286 | case 25: /* See invisible */ 287 | 288 | if (Blind) { 289 | if (Invisible) { 290 | You("feel very self-conscious."); 291 | pline("Then it passes."); 292 | } else { 293 | You("feel transparent."); 294 | } 295 | } else { 296 | You("see an image of someone stalking you."); 297 | pline("But it disappears."); 298 | } 299 | HSee_invisible |= FROMOUTSIDE; 300 | newsym(u.ux,u.uy); 301 | exercise(A_WIS, TRUE); 302 | break; 303 | 304 | case 26: /* See Monsters */ 305 | 306 | (void) monster_detect((struct obj *)0, 0); 307 | exercise(A_WIS, TRUE); 308 | break; 309 | 310 | case 27: /* Find a gem in the sparkling waters. */ 311 | 312 | if (!levl[u.ux][u.uy].looted) { 313 | dofindgem(); 314 | break; 315 | } 316 | 317 | case 28: /* Water Nymph */ 318 | 319 | dowaternymph(); 320 | break; 321 | 322 | case 29: /* Scare */ { 323 | register struct monst *mtmp; 324 | 325 | pline("This water gives you bad breath!"); 326 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) 327 | if(!DEADMONSTER(mtmp)) 328 | mtmp->mflee = 1; 329 | } 330 | break; 331 | 332 | case 30: /* Gushing forth in this room */ 333 | 334 | dogushforth(TRUE); 335 | break; 336 | 337 | default: 338 | 339 | pline("This tepid water is tasteless."); 340 | break; 341 | } 342 | } 343 | dryup(u.ux, u.uy, TRUE); 344 | } 345 | 346 | void 347 | dipfountain(obj) 348 | register struct obj *obj; 349 | { 350 | if (Levitation) { 351 | floating_above("fountain"); 352 | return; 353 | } 354 | 355 | /* Don't grant Excalibur when there's more than one object. */ 356 | /* (quantity could be > 1 if merged daggers got polymorphed) */ 357 | if (obj->otyp == LONG_SWORD && obj->quan == 1L 358 | && u.ulevel >= 5 && !rn2(6) 359 | && !obj->oartifact 360 | && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) { 361 | s_level *slev = Is_special(&u.uz); 362 | 363 | if (u.ualign.type != A_LAWFUL) { 364 | /* Ha! Trying to cheat her. */ 365 | pline("A freezing mist rises from the water and envelopes the sword."); 366 | pline_The("fountain disappears!"); 367 | curse(obj); 368 | if (obj->spe > -6 && !rn2(3)) obj->spe--; 369 | obj->oerodeproof = FALSE; 370 | exercise(A_WIS, FALSE); 371 | } else { 372 | /* The lady of the lake acts! - Eric Backus */ 373 | /* Be *REAL* nice */ 374 | pline("From the murky depths, a hand reaches up to bless the sword."); 375 | pline("As the hand retreats, the fountain disappears!"); 376 | obj = oname(obj, artiname(ART_EXCALIBUR)); 377 | discover_artifact(ART_EXCALIBUR); 378 | bless(obj); 379 | obj->oeroded = obj->oeroded2 = 0; 380 | obj->oerodeproof = TRUE; 381 | exercise(A_WIS, TRUE); 382 | } 383 | levl[u.ux][u.uy].typ = ROOM; 384 | levl[u.ux][u.uy].looted = 0; 385 | if(Invisible) newsym(u.ux, u.uy); 386 | level.flags.nfountains--; 387 | if(slev && slev->flags.town) 388 | (void) angry_guards(FALSE); 389 | return; 390 | } else (void) get_wet(obj); 391 | 392 | /* Acid and water don't mix */ 393 | if (obj->otyp == POT_ACID) { 394 | useup(obj); 395 | return; 396 | } 397 | 398 | switch (rnd(30)) { 399 | case 16: /* Curse the item */ 400 | curse(obj); 401 | break; 402 | case 17: 403 | case 18: 404 | case 19: 405 | case 20: /* Uncurse the item */ 406 | if(obj->cursed) { 407 | if (!Blind) 408 | pline_The("water glows for a moment."); 409 | uncurse(obj); 410 | } else { 411 | pline("A feeling of loss comes over you."); 412 | } 413 | break; 414 | case 21: /* Water Demon */ 415 | dowaterdemon(); 416 | break; 417 | case 22: /* Water Nymph */ 418 | dowaternymph(); 419 | break; 420 | case 23: /* an Endless Stream of Snakes */ 421 | dowatersnakes(); 422 | break; 423 | case 24: /* Find a gem */ 424 | if (!levl[u.ux][u.uy].looted) { 425 | dofindgem(); 426 | break; 427 | } 428 | case 25: /* Water gushes forth */ 429 | dogushforth(FALSE); 430 | break; 431 | case 26: /* Strange feeling */ 432 | pline("A strange tingling runs up your %s.", 433 | body_part(ARM)); 434 | break; 435 | case 27: /* Strange feeling */ 436 | You_feel("a sudden chill."); 437 | break; 438 | case 28: /* Strange feeling */ 439 | pline("An urge to take a bath overwhelms you."); 440 | if (u.ugold > 10) { 441 | u.ugold -= somegold() / 10; 442 | You("lost some of your gold in the fountain!"); 443 | levl[u.ux][u.uy].looted &= ~F_LOOTED; 444 | exercise(A_WIS, FALSE); 445 | } 446 | break; 447 | case 29: /* You see coins */ 448 | 449 | /* We make fountains have more coins the closer you are to the 450 | * surface. After all, there will have been more people going 451 | * by. Just like a shopping mall! Chris Woodbury */ 452 | 453 | if (levl[u.ux][u.uy].looted) break; 454 | levl[u.ux][u.uy].looted |= F_LOOTED; 455 | (void) mkgold((long) 456 | (rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5), 457 | u.ux, u.uy); 458 | if (!Blind) 459 | pline("Far below you, you see coins glistening in the water."); 460 | exercise(A_WIS, TRUE); 461 | newsym(u.ux,u.uy); 462 | break; 463 | } 464 | dryup(u.ux, u.uy, TRUE); 465 | } 466 | 467 | #ifdef SINKS 468 | void 469 | breaksink(x,y) 470 | int x, y; 471 | { 472 | if(cansee(x,y) || (x == u.ux && y == u.uy)) 473 | pline_The("pipes break! Water spurts out!"); 474 | level.flags.nsinks--; 475 | levl[x][y].doormask = 0; 476 | levl[x][y].typ = FOUNTAIN; 477 | level.flags.nfountains++; 478 | newsym(x,y); 479 | } 480 | 481 | void 482 | drinksink() 483 | { 484 | struct obj *otmp; 485 | struct monst *mtmp; 486 | 487 | if (Levitation) { 488 | floating_above("sink"); 489 | return; 490 | } 491 | switch(rn2(20)) { 492 | case 0: You("take a sip of very cold water."); 493 | break; 494 | case 1: You("take a sip of very warm water."); 495 | break; 496 | case 2: You("take a sip of scalding hot water."); 497 | if (Fire_resistance) 498 | pline("It seems quite tasty."); 499 | else losehp(rnd(6), "sipping boiling water", KILLED_BY); 500 | break; 501 | case 3: if (mvitals[PM_SEWER_RAT].mvflags & G_GONE) 502 | pline_The("sink seems quite dirty."); 503 | else { 504 | mtmp = makemon(&mons[PM_SEWER_RAT], 505 | u.ux, u.uy, NO_MM_FLAGS); 506 | pline("Eek! There's %s in the sink!", 507 | Blind ? "something squirmy" : 508 | a_monnam(mtmp)); 509 | } 510 | break; 511 | case 4: do { 512 | otmp = mkobj(POTION_CLASS,FALSE); 513 | if (otmp->otyp == POT_WATER) { 514 | obfree(otmp, (struct obj *)0); 515 | otmp = (struct obj *) 0; 516 | } 517 | } while(!otmp); 518 | otmp->cursed = otmp->blessed = 0; 519 | pline("Some %s liquid flows from the faucet.", 520 | Blind ? "odd" : 521 | hcolor(OBJ_DESCR(objects[otmp->otyp]))); 522 | otmp->dknown = !(Blind || Hallucination); 523 | otmp->quan++; /* Avoid panic upon useup() */ 524 | otmp->corpsenm = 1; /* kludge for docall() */ 525 | (void) dopotion(otmp); 526 | obfree(otmp, (struct obj *)0); 527 | break; 528 | case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) { 529 | You("find a ring in the sink!"); 530 | (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE); 531 | levl[u.ux][u.uy].looted |= S_LRING; 532 | exercise(A_WIS, TRUE); 533 | newsym(u.ux,u.uy); 534 | } else pline("Some dirty water backs up in the drain."); 535 | break; 536 | case 6: breaksink(u.ux,u.uy); 537 | break; 538 | case 7: pline_The("water moves as though of its own will!"); 539 | if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE) 540 | || !makemon(&mons[PM_WATER_ELEMENTAL], 541 | u.ux, u.uy, NO_MM_FLAGS)) 542 | pline("But it quiets down."); 543 | break; 544 | case 8: pline("Yuk, this water tastes awful."); 545 | more_experienced(1,0); 546 | newexplevel(); 547 | break; 548 | case 9: pline("Gaggg... this tastes like sewage! You vomit."); 549 | morehungry(rn1(30-ACURR(A_CON), 11)); 550 | vomit(); 551 | break; 552 | case 10: pline("This water contains toxic wastes!"); 553 | if (!Unchanging) { 554 | You("undergo a freakish metamorphosis!"); 555 | polyself(); 556 | } 557 | break; 558 | /* more odd messages --JJB */ 559 | case 11: You_hear("clanking from the pipes..."); 560 | break; 561 | case 12: You_hear("snatches of song from among the sewers..."); 562 | break; 563 | case 19: if (Hallucination) { 564 | pline("From the murky drain, a hand reaches up... --oops--"); 565 | break; 566 | } 567 | default: You("take a sip of %s water.", 568 | rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot"); 569 | } 570 | } 571 | #endif /* SINKS */ 572 | 573 | /*fountain.c*/