xref: /netbsd-src/games/hack/hack.read.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: hack.read.c,v 1.8 2003/04/02 18:36:39 jsm Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.read.c,v 1.8 2003/04/02 18:36:39 jsm Exp $");
67 #endif				/* not lint */
68 
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 
73 int
74 doread()
75 {
76 	struct obj     *scroll;
77 	boolean         confused = (Confusion != 0);
78 	boolean         known = FALSE;
79 
80 	scroll = getobj("?", "read");
81 	if (!scroll)
82 		return (0);
83 	if (!scroll->dknown && Blind) {
84 		pline("Being blind, you cannot read the formula on the scroll.");
85 		return (0);
86 	}
87 	if (Blind)
88 		pline("As you pronounce the formula on it, the scroll disappears.");
89 	else
90 		pline("As you read the scroll, it disappears.");
91 	if (confused)
92 		pline("Being confused, you mispronounce the magic words ... ");
93 
94 	switch (scroll->otyp) {
95 #ifdef MAIL
96 	case SCR_MAIL:
97 		readmail( /* scroll */ );
98 		break;
99 #endif	/* MAIL */
100 	case SCR_ENCHANT_ARMOR:
101 		{
102 			struct obj     *otmp = some_armor();
103 			if (!otmp) {
104 				strange_feeling(scroll, "Your skin glows then fades.");
105 				return (1);
106 			}
107 			if (confused) {
108 				pline("Your %s glows silver for a moment.",
109 				      objects[otmp->otyp].oc_name);
110 				otmp->rustfree = 1;
111 				break;
112 			}
113 			if (otmp->spe > 3 && rn2(otmp->spe)) {
114 				pline("Your %s glows violently green for a while, then evaporates.",
115 				      objects[otmp->otyp].oc_name);
116 				useup(otmp);
117 				break;
118 			}
119 			pline("Your %s glows green for a moment.",
120 			      objects[otmp->otyp].oc_name);
121 			otmp->cursed = 0;
122 			otmp->spe++;
123 			break;
124 		}
125 	case SCR_DESTROY_ARMOR:
126 		if (confused) {
127 			struct obj     *otmp = some_armor();
128 			if (!otmp) {
129 				strange_feeling(scroll, "Your bones itch.");
130 				return (1);
131 			}
132 			pline("Your %s glows purple for a moment.",
133 			      objects[otmp->otyp].oc_name);
134 			otmp->rustfree = 0;
135 			break;
136 		}
137 		if (uarm) {
138 			pline("Your armor turns to dust and falls to the floor!");
139 			useup(uarm);
140 		} else if (uarmh) {
141 			pline("Your helmet turns to dust and is blown away!");
142 			useup(uarmh);
143 		} else if (uarmg) {
144 			pline("Your gloves vanish!");
145 			useup(uarmg);
146 			selftouch("You");
147 		} else {
148 			strange_feeling(scroll, "Your skin itches.");
149 			return (1);
150 		}
151 		break;
152 	case SCR_CONFUSE_MONSTER:
153 		if (confused) {
154 			pline("Your hands begin to glow purple.");
155 			Confusion += rnd(100);
156 		} else {
157 			pline("Your hands begin to glow blue.");
158 			u.umconf = 1;
159 		}
160 		break;
161 	case SCR_SCARE_MONSTER:
162 		{
163 			int             ct = 0;
164 			struct monst   *mtmp;
165 
166 			for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
167 				if (cansee(mtmp->mx, mtmp->my)) {
168 					if (confused)
169 						mtmp->mflee = mtmp->mfroz =
170 							mtmp->msleep = 0;
171 					else
172 						mtmp->mflee = 1;
173 					ct++;
174 				}
175 			if (!ct) {
176 				if (confused)
177 					pline("You hear sad wailing in the distance.");
178 				else
179 					pline("You hear maniacal laughter in the distance.");
180 			}
181 			break;
182 		}
183 	case SCR_BLANK_PAPER:
184 		if (confused)
185 			pline("You see strange patterns on this scroll.");
186 		else
187 			pline("This scroll seems to be blank.");
188 		break;
189 	case SCR_REMOVE_CURSE:
190 		{
191 			struct obj     *obj;
192 			if (confused)
193 				pline("You feel like you need some help.");
194 			else
195 				pline("You feel like someone is helping you.");
196 			for (obj = invent; obj; obj = obj->nobj)
197 				if (obj->owornmask)
198 					obj->cursed = confused;
199 			if (Punished && !confused) {
200 				Punished = 0;
201 				freeobj(uchain);
202 				unpobj(uchain);
203 				free((char *) uchain);
204 				uball->spe = 0;
205 				uball->owornmask &= ~W_BALL;
206 				uchain = uball = (struct obj *) 0;
207 			}
208 			break;
209 		}
210 	case SCR_CREATE_MONSTER:
211 		{
212 			int             cnt = 1;
213 
214 			if (!rn2(73))
215 				cnt += rnd(4);
216 			if (confused)
217 				cnt += 12;
218 			while (cnt--)
219 				(void) makemon(confused ? PM_ACID_BLOB :
220 					 (struct permonst *) 0, u.ux, u.uy);
221 			break;
222 		}
223 	case SCR_ENCHANT_WEAPON:
224 		if (uwep && confused) {
225 			pline("Your %s glows silver for a moment.",
226 			      objects[uwep->otyp].oc_name);
227 			uwep->rustfree = 1;
228 		} else if (!chwepon(scroll, 1))	/* tests for !uwep */
229 			return (1);
230 		break;
231 	case SCR_DAMAGE_WEAPON:
232 		if (uwep && confused) {
233 			pline("Your %s glows purple for a moment.",
234 			      objects[uwep->otyp].oc_name);
235 			uwep->rustfree = 0;
236 		} else if (!chwepon(scroll, -1))	/* tests for !uwep */
237 			return (1);
238 		break;
239 	case SCR_TAMING:
240 		{
241 			int             i, j;
242 			int             bd = confused ? 5 : 1;
243 			struct monst   *mtmp;
244 
245 			for (i = -bd; i <= bd; i++)
246 				for (j = -bd; j <= bd; j++)
247 					if ((mtmp = m_at(u.ux + i, u.uy + j)) != NULL)
248 						(void) tamedog(mtmp, (struct obj *) 0);
249 			break;
250 		}
251 	case SCR_GENOCIDE:
252 		{
253 			char            buf[BUFSZ];
254 			struct monst   *mtmp, *mtmp2;
255 
256 			pline("You have found a scroll of genocide!");
257 			known = TRUE;
258 			if (confused)
259 				*buf = u.usym;
260 			else
261 				do {
262 					pline("What monster do you want to genocide (Type the letter)? ");
263 					getlin(buf);
264 				} while (strlen(buf) != 1 || !monstersym(*buf));
265 			if (!strchr(fut_geno, *buf))
266 				charcat(fut_geno, *buf);
267 			if (!strchr(genocided, *buf))
268 				charcat(genocided, *buf);
269 			else {
270 				pline("Such monsters do not exist in this world.");
271 				break;
272 			}
273 			for (mtmp = fmon; mtmp; mtmp = mtmp2) {
274 				mtmp2 = mtmp->nmon;
275 				if (mtmp->data->mlet == *buf)
276 					mondead(mtmp);
277 			}
278 			pline("Wiped out all %c's.", *buf);
279 			if (*buf == u.usym) {
280 				killer = "scroll of genocide";
281 				u.uhp = -1;
282 			}
283 			break;
284 		}
285 	case SCR_LIGHT:
286 		if (!Blind)
287 			known = TRUE;
288 		litroom(!confused);
289 		break;
290 	case SCR_TELEPORTATION:
291 		if (confused)
292 			level_tele();
293 		else {
294 #ifdef QUEST
295 			int             oux = u.ux, ouy = u.uy;
296 			tele();
297 			if (dist(oux, ouy) > 100)
298 				known = TRUE;
299 #else	/* QUEST */
300 			int             uroom = inroom(u.ux, u.uy);
301 			tele();
302 			if (uroom != inroom(u.ux, u.uy))
303 				known = TRUE;
304 #endif	/* QUEST */
305 		}
306 		break;
307 	case SCR_GOLD_DETECTION:
308 		/*
309 		 * Unfortunately this code has become slightly less elegant,
310 		 * now that gold and traps no longer are of the same type.
311 		 */
312 		if (confused) {
313 			struct trap    *ttmp;
314 
315 			if (!ftrap) {
316 				strange_feeling(scroll, "Your toes stop itching.");
317 				return (1);
318 			} else {
319 				for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
320 					if (ttmp->tx != u.ux || ttmp->ty != u.uy)
321 						goto outtrapmap;
322 				/*
323 				 * only under me - no separate display
324 				 * required
325 				 */
326 				pline("Your toes itch!");
327 				break;
328 		outtrapmap:
329 				cls();
330 				for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
331 					at(ttmp->tx, ttmp->ty, '$');
332 				prme();
333 				pline("You feel very greedy!");
334 			}
335 		} else {
336 			struct gold    *gtmp;
337 
338 			if (!fgold) {
339 				strange_feeling(scroll, "You feel materially poor.");
340 				return (1);
341 			} else {
342 				known = TRUE;
343 				for (gtmp = fgold; gtmp; gtmp = gtmp->ngold)
344 					if (gtmp->gx != u.ux || gtmp->gy != u.uy)
345 						goto outgoldmap;
346 				/*
347 				 * only under me - no separate display
348 				 * required
349 				 */
350 				pline("You notice some gold between your feet.");
351 				break;
352 		outgoldmap:
353 				cls();
354 				for (gtmp = fgold; gtmp; gtmp = gtmp->ngold)
355 					at(gtmp->gx, gtmp->gy, '$');
356 				prme();
357 				pline("You feel very greedy, and sense gold!");
358 			}
359 		}
360 		/* common sequel */
361 		more();
362 		docrt();
363 		break;
364 	case SCR_FOOD_DETECTION:
365 		{
366 			int ct = 0, ctu = 0;
367 			struct obj     *obj;
368 			char            foodsym = confused ? POTION_SYM : FOOD_SYM;
369 
370 			for (obj = fobj; obj; obj = obj->nobj)
371 				if (obj->olet == FOOD_SYM) {
372 					if (obj->ox == u.ux && obj->oy == u.uy)
373 						ctu++;
374 					else
375 						ct++;
376 				}
377 			if (!ct && !ctu) {
378 				strange_feeling(scroll, "Your nose twitches.");
379 				return (1);
380 			} else if (!ct) {
381 				known = TRUE;
382 				pline("You smell %s close nearby.",
383 				      confused ? "something" : "food");
384 
385 			} else {
386 				known = TRUE;
387 				cls();
388 				for (obj = fobj; obj; obj = obj->nobj)
389 					if (obj->olet == foodsym)
390 						at(obj->ox, obj->oy, FOOD_SYM);
391 				prme();
392 				pline("Your nose tingles and you smell %s!",
393 				      confused ? "something" : "food");
394 				more();
395 				docrt();
396 			}
397 			break;
398 		}
399 	case SCR_IDENTIFY:
400 		/* known = TRUE; */
401 		if (confused)
402 			pline("You identify this as an identify scroll.");
403 		else
404 			pline("This is an identify scroll.");
405 		useup(scroll);
406 		objects[SCR_IDENTIFY].oc_name_known = 1;
407 		if (!confused)
408 			while (
409 			 !ggetobj("identify", identify, rn2(5) ? 1 : rn2(5))
410 			       && invent
411 				);
412 		return (1);
413 	case SCR_MAGIC_MAPPING:
414 		{
415 			struct rm      *lev;
416 			int             num, zx, zy;
417 
418 			known = TRUE;
419 			pline("On this scroll %s a map!",
420 			      confused ? "was" : "is");
421 			for (zy = 0; zy < ROWNO; zy++)
422 				for (zx = 0; zx < COLNO; zx++) {
423 					if (confused && rn2(7))
424 						continue;
425 					lev = &(levl[zx][zy]);
426 					if ((num = lev->typ) == 0)
427 						continue;
428 					if (num == SCORR) {
429 						lev->typ = CORR;
430 						lev->scrsym = CORR_SYM;
431 					} else if (num == SDOOR) {
432 						lev->typ = DOOR;
433 						lev->scrsym = '+';
434 						/* do sth in doors ? */
435 					} else if (lev->seen)
436 						continue;
437 #ifndef QUEST
438 					if (num != ROOM)
439 #endif	/* QUEST */
440 					{
441 						lev->seen = lev->new = 1;
442 						if (lev->scrsym == ' ' || !lev->scrsym)
443 							newsym(zx, zy);
444 						else
445 							on_scr(zx, zy);
446 					}
447 				}
448 			break;
449 		}
450 	case SCR_AMNESIA:
451 		{
452 			int             zx, zy;
453 
454 			known = TRUE;
455 			for (zx = 0; zx < COLNO; zx++)
456 				for (zy = 0; zy < ROWNO; zy++)
457 					if (!confused || rn2(7))
458 						if (!cansee(zx, zy))
459 							levl[zx][zy].seen = 0;
460 			docrt();
461 			pline("Thinking of Maud you forget everything else.");
462 			break;
463 		}
464 	case SCR_FIRE:
465 		{
466 			int             num = 0;
467 			struct monst   *mtmp;
468 
469 			known = TRUE;
470 			if (confused) {
471 				pline("The scroll catches fire and you burn your hands.");
472 				losehp(1, "scroll of fire");
473 			} else {
474 				pline("The scroll erupts in a tower of flame!");
475 				if (Fire_resistance)
476 					pline("You are uninjured.");
477 				else {
478 					num = rnd(6);
479 					u.uhpmax -= num;
480 					losehp(num, "scroll of fire");
481 				}
482 			}
483 			num = (2 * num + 1) / 3;
484 			for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
485 				if (dist(mtmp->mx, mtmp->my) < 3) {
486 					mtmp->mhp -= num;
487 					if (strchr("FY", mtmp->data->mlet))
488 						mtmp->mhp -= 3 * num;	/* this might well kill
489 									 * 'F's */
490 					if (mtmp->mhp < 1) {
491 						killed(mtmp);
492 						break;	/* primitive */
493 					}
494 				}
495 			}
496 			break;
497 		}
498 	case SCR_PUNISHMENT:
499 		known = TRUE;
500 		if (confused) {
501 			pline("You feel guilty.");
502 			break;
503 		}
504 		pline("You are being punished for your misbehaviour!");
505 		if (Punished) {
506 			pline("Your iron ball gets heavier.");
507 			uball->owt += 15;
508 			break;
509 		}
510 		Punished = INTRINSIC;
511 		setworn(mkobj_at(CHAIN_SYM, u.ux, u.uy), W_CHAIN);
512 		setworn(mkobj_at(BALL_SYM, u.ux, u.uy), W_BALL);
513 		uball->spe = 1;	/* special ball (see save) */
514 		break;
515 	default:
516 		impossible("What weird language is this written in? (%u)",
517 			   scroll->otyp);
518 	}
519 	if (!objects[scroll->otyp].oc_name_known) {
520 		if (known && !confused) {
521 			objects[scroll->otyp].oc_name_known = 1;
522 			more_experienced(0, 10);
523 		} else if (!objects[scroll->otyp].oc_uname)
524 			docall(scroll);
525 	}
526 	useup(scroll);
527 	return (1);
528 }
529 
530 int
531 identify(otmp)			/* also called by newmail() */
532 	struct obj     *otmp;
533 {
534 	objects[otmp->otyp].oc_name_known = 1;
535 	otmp->known = otmp->dknown = 1;
536 	prinv(otmp);
537 	return (1);
538 }
539 
540 void
541 litroom(on)
542 	boolean         on;
543 {
544 #ifndef QUEST
545 	int num, zx, zy;
546 #endif
547 
548 	/* first produce the text (provided he is not blind) */
549 	if (Blind)
550 		goto do_it;
551 	if (!on) {
552 		if (u.uswallow || !xdnstair || levl[u.ux][u.uy].typ == CORR ||
553 		    !levl[u.ux][u.uy].lit) {
554 			pline("It seems even darker in here than before.");
555 			return;
556 		} else
557 			pline("It suddenly becomes dark in here.");
558 	} else {
559 		if (u.uswallow) {
560 			pline("%s's stomach is lit.", Monnam(u.ustuck));
561 			return;
562 		}
563 		if (!xdnstair) {
564 			pline("Nothing Happens.");
565 			return;
566 		}
567 #ifdef QUEST
568 		pline("The cave lights up around you, then fades.");
569 		return;
570 #else	/* QUEST */
571 		if (levl[u.ux][u.uy].typ == CORR) {
572 			pline("The corridor lights up around you, then fades.");
573 			return;
574 		} else if (levl[u.ux][u.uy].lit) {
575 			pline("The light here seems better now.");
576 			return;
577 		} else
578 			pline("The room is lit.");
579 #endif	/* QUEST */
580 	}
581 
582 do_it:
583 #ifdef QUEST
584 	return;
585 #else	/* QUEST */
586 	if (levl[u.ux][u.uy].lit == on)
587 		return;
588 	if (levl[u.ux][u.uy].typ == DOOR) {
589 		if (IS_ROOM(levl[u.ux][u.uy + 1].typ))
590 			zy = u.uy + 1;
591 		else if (IS_ROOM(levl[u.ux][u.uy - 1].typ))
592 			zy = u.uy - 1;
593 		else
594 			zy = u.uy;
595 		if (IS_ROOM(levl[u.ux + 1][u.uy].typ))
596 			zx = u.ux + 1;
597 		else if (IS_ROOM(levl[u.ux - 1][u.uy].typ))
598 			zx = u.ux - 1;
599 		else
600 			zx = u.ux;
601 	} else {
602 		zx = u.ux;
603 		zy = u.uy;
604 	}
605 	for (seelx = u.ux; (num = levl[seelx - 1][zy].typ) != CORR && num != 0;
606 	     seelx--);
607 	for (seehx = u.ux; (num = levl[seehx + 1][zy].typ) != CORR && num != 0;
608 	     seehx++);
609 	for (seely = u.uy; (num = levl[zx][seely - 1].typ) != CORR && num != 0;
610 	     seely--);
611 	for (seehy = u.uy; (num = levl[zx][seehy + 1].typ) != CORR && num != 0;
612 	     seehy++);
613 	for (zy = seely; zy <= seehy; zy++)
614 		for (zx = seelx; zx <= seehx; zx++) {
615 			levl[zx][zy].lit = on;
616 			if (!Blind && dist(zx, zy) > 2) {
617 				if (on)
618 					prl(zx, zy);
619 				else
620 					nosee(zx, zy);
621 			}
622 		}
623 	if (!on)
624 		seehx = 0;
625 #endif	/* QUEST */
626 }
627 
628 /* Test whether we may genocide all monsters with symbol  ch  */
629 int
630 monstersym(ch)			/* arnold@ucsfcgl */
631 	char            ch;
632 {
633 	const struct permonst *mp;
634 
635 	/*
636 	 * can't genocide certain monsters
637 	 */
638 	if (strchr("12 &:", ch))
639 		return FALSE;
640 
641 	if (ch == pm_eel.mlet)
642 		return TRUE;
643 	for (mp = mons; mp < &mons[CMNUM + 2]; mp++)
644 		if (mp->mlet == ch)
645 			return TRUE;
646 	return FALSE;
647 }
648