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