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