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