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