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