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