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*/