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