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