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
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
floating_above(what)16 floating_above(what)
17 const char *what;
18 {
19 You("are floating high above the %s.", what);
20 }
21
22 STATIC_OVL void
dowatersnakes()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
dowaterdemon()44 dowaterdemon() /* 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(FALSE);
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
68 STATIC_OVL void
dowaternymph()69 dowaternymph() /* 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
89 void
dogushforth(drinking)90 dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */
91 int 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
104 STATIC_PTR void
gush(x,y,poolcnt)105 gush(x, y, poolcnt)
106 int x, y;
107 genericptr_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
136 STATIC_OVL void
dofindgem()137 dofindgem() /* 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
148 void
dryup(x,y,isyou)149 dryup(x, y, isyou)
150 xchar x, y;
151 boolean 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
194 void
drinkfountain()195 drinkfountain()
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, TRUE);
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
350 void
dipfountain(obj)351 dipfountain(obj)
352 register 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
496 void
breaksink(x,y)497 breaksink(x,y)
498 int 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
509 void
drinksink()510 drinksink()
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 /* use Luck here instead of u.uluck */
542 if (!rn2(13) && ((Luck >= 0 && maybe_polyd(is_vampire(youmonst.data), Race_if(PM_VAMPIRE))) ||
543 (Luck <= 0 && !maybe_polyd(is_vampire(youmonst.data), Race_if(PM_VAMPIRE))))) {
544 otmp = mksobj(POT_VAMPIRE_BLOOD,FALSE,FALSE);
545 } else {
546 otmp = mkobj(POTION_CLASS,FALSE);
547 if (otmp->otyp == POT_WATER) {
548 obfree(otmp, (struct obj *)0);
549 otmp = (struct obj *) 0;
550 }
551 }
552 } while(!otmp);
553 if (rnf(1,Luck+17)) otmp->cursed = 1;
554 else if (rnf(1,17-Luck)) otmp->blessed = 1;
555 else otmp->cursed = otmp->blessed = 0;
556 pline("Some %s liquid flows from the faucet.",
557 Blind ? "odd" :
558 hcolor(OBJ_DESCR(objects[otmp->otyp])));
559 otmp->dknown = !(Blind || Hallucination);
560 otmp->quan++; /* Avoid panic upon useup() */
561 otmp->fromsink = 1; /* kludge for docall() */
562 (void) dopotion(otmp);
563 obfree(otmp, (struct obj *)0);
564 break;
565 case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) {
566 You("find a ring in the sink!");
567 (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE);
568 levl[u.ux][u.uy].looted |= S_LRING;
569 exercise(A_WIS, TRUE);
570 newsym(u.ux,u.uy);
571 } else pline("Some dirty water backs up in the drain.");
572 break;
573 case 6: breaksink(u.ux,u.uy);
574 break;
575 case 7: pline_The("water moves as though of its own will!");
576 if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
577 || !makemon(&mons[PM_WATER_ELEMENTAL],
578 u.ux, u.uy, NO_MM_FLAGS))
579 pline("But it quiets down.");
580 break;
581 case 8: pline("Yuk, this water tastes awful.");
582 more_experienced(1,1,0);
583 newexplevel();
584 break;
585 case 9: pline("Gaggg... this tastes like sewage! You vomit.");
586 morehungry(rn1(30-ACURR(A_CON), 11));
587 vomit();
588 break;
589 case 10: pline("This water contains toxic wastes!");
590 if (!Unchanging) {
591 You("undergo a freakish metamorphosis!");
592 polyself(FALSE);
593 }
594 break;
595 /* more odd messages --JJB */
596 case 11: You_hear("clanking from the pipes...");
597 break;
598 case 12: You_hear("snatches of song from among the sewers...");
599 break;
600 case 19: if (Hallucination) {
601 pline("From the murky drain, a hand reaches up... --oops--");
602 break;
603 }
604 default: You("take a sip of %s water.",
605 rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot");
606 }
607 }
608 #endif /* SINKS */
609
610 /*fountain.c*/
611