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