1/*	SCCS Id: @(#)read.c	3.4	2003/10/22	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5#include "hack.h"
6
7/* KMH -- Copied from pray.c; this really belongs in a header file */
8#define DEVOUT 14
9#define STRIDENT 4
10
11#define Your_Own_Role(mndx) \
12	((mndx) == urole.malenum || \
13	 (urole.femalenum != NON_PM && (mndx) == urole.femalenum))
14#define Your_Own_Race(mndx) \
15	((mndx) == urace.malenum || \
16	 (urace.femalenum != NON_PM && (mndx) == urace.femalenum))
17
18#ifdef OVLB
19
20boolean	known;
21
22static NEARDATA const char readable[] =
23		   { ALL_CLASSES, SCROLL_CLASS, SPBOOK_CLASS, 0 };
24static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
25
26static void FDECL(wand_explode, (struct obj *));
27static void NDECL(do_class_genocide);
28static void FDECL(stripspe,(struct obj *));
29static void FDECL(p_glow1,(struct obj *));
30static void FDECL(p_glow2,(struct obj *,const char *));
31static void FDECL(randomize,(int *, int));
32static void FDECL(forget_single_object, (int));
33static void FDECL(forget, (int));
34static void FDECL(maybe_tame, (struct monst *,struct obj *));
35
36STATIC_PTR void FDECL(set_lit, (int,int,genericptr_t));
37
38int
39doread()
40{
41	register struct obj *scroll;
42	register boolean confused;
43
44	known = FALSE;
45	if(check_capacity((char *)0)) return (0);
46	scroll = getobj(readable, "read");
47	if(!scroll) return(0);
48
49	/* outrumor has its own blindness check */
50	if(scroll->otyp == FORTUNE_COOKIE) {
51	    if(flags.verbose)
52		You("break up the cookie and throw away the pieces.");
53	    outrumor(bcsign(scroll), BY_COOKIE);
54	    if (!Blind) u.uconduct.literate++;
55	    useup(scroll);
56	    return(1);
57#ifdef TOURIST
58	} else if (scroll->otyp == T_SHIRT) {
59	    static const char *shirt_msgs[] = { /* Scott Bigham */
60    "I explored the Dungeons of Doom and all I got was this lousy T-shirt!",
61    "Is that Mjollnir in your pocket or are you just happy to see me?",
62    "It's not the size of your sword, it's how #enhance'd you are with it.",
63    "Madame Elvira's House O' Succubi Lifetime Customer",
64    "Madame Elvira's House O' Succubi Employee of the Month",
65    "Ludios Vault Guards Do It In Small, Dark Rooms",
66    "Yendor Military Soldiers Do It In Large Groups",
67    "I survived Yendor Military Boot Camp",
68    "Ludios Accounting School Intra-Mural Lacrosse Team",
69    "Oracle(TM) Fountains 10th Annual Wet T-Shirt Contest",
70    "Hey, black dragon!  Disintegrate THIS!",
71    "I'm With Stupid -->",
72    "Don't blame me, I voted for Izchak!",
73    "Don't Panic",				/* HHGTTG */
74    "Furinkan High School Athletic Dept.",	/* Ranma 1/2 */
75    "Hel-LOOO, Nurse!",			/* Animaniacs */
76	    };
77	    char buf[BUFSZ];
78	    int erosion;
79
80	    if (Blind) {
81		You_cant("feel any Braille writing.");
82		return 0;
83	    }
84	    u.uconduct.literate++;
85	    if(flags.verbose)
86		pline("It reads:");
87	    Strcpy(buf, shirt_msgs[scroll->o_id % SIZE(shirt_msgs)]);
88	    erosion = greatest_erosion(scroll);
89	    if (erosion)
90		wipeout_text(buf,
91			(int)(strlen(buf) * erosion / (2*MAX_ERODE)),
92			     scroll->o_id ^ (unsigned)u.ubirthday);
93	    pline("\"%s\"", buf);
94	    return 1;
95#endif	/* TOURIST */
96	} else if (scroll->oclass != SCROLL_CLASS
97		&& scroll->oclass != SPBOOK_CLASS) {
98	    pline(silly_thing_to, "read");
99	    return(0);
100	} else if (Blind) {
101	    const char *what = 0;
102	    if (scroll->oclass == SPBOOK_CLASS)
103		what = "mystic runes";
104	    else if (!scroll->dknown)
105		what = "formula on the scroll";
106	    if (what) {
107		pline("Being blind, you cannot read the %s.", what);
108		return(0);
109	    }
110	}
111
112	/* Actions required to win the game aren't counted towards conduct */
113	if (scroll->otyp != SPE_BOOK_OF_THE_DEAD &&
114		scroll->otyp != SPE_BLANK_PAPER &&
115		scroll->otyp != SCR_BLANK_PAPER)
116	    u.uconduct.literate++;
117
118	confused = (Confusion != 0);
119#ifdef MAIL
120	if (scroll->otyp == SCR_MAIL) confused = FALSE;
121#endif
122	if(scroll->oclass == SPBOOK_CLASS) {
123	    return(study_book(scroll));
124	}
125	scroll->in_use = TRUE;	/* scroll, not spellbook, now being read */
126	if(scroll->otyp != SCR_BLANK_PAPER) {
127	  if(Blind)
128	    pline("As you %s the formula on it, the scroll disappears.",
129			is_silent(youmonst.data) ? "cogitate" : "pronounce");
130	  else
131	    pline("As you read the scroll, it disappears.");
132	  if(confused) {
133	    if (Hallucination)
134		pline("Being so trippy, you screw up...");
135	    else
136		pline("Being confused, you mis%s the magic words...",
137			is_silent(youmonst.data) ? "understand" : "pronounce");
138	  }
139	}
140	if(!seffects(scroll))  {
141		if(!objects[scroll->otyp].oc_name_known) {
142		    if(known) {
143			makeknown(scroll->otyp);
144			more_experienced(0,10);
145		    } else if(!objects[scroll->otyp].oc_uname)
146			docall(scroll);
147		}
148		if(scroll->otyp != SCR_BLANK_PAPER)
149			useup(scroll);
150		else scroll->in_use = FALSE;
151	}
152	return(1);
153}
154
155static void
156stripspe(obj)
157register struct obj *obj;
158{
159	if (obj->blessed) pline(nothing_happens);
160	else {
161		if (obj->spe > 0) {
162		    obj->spe = 0;
163		    if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN)
164			obj->age = 0;
165		    Your("%s %s briefly.",xname(obj), otense(obj, "vibrate"));
166		} else pline(nothing_happens);
167	}
168}
169
170static void
171p_glow1(otmp)
172register struct obj	*otmp;
173{
174	Your("%s %s briefly.", xname(otmp),
175	     otense(otmp, Blind ? "vibrate" : "glow"));
176}
177
178static void
179p_glow2(otmp,color)
180register struct obj	*otmp;
181register const char *color;
182{
183	Your("%s %s%s%s for a moment.",
184		xname(otmp),
185		otense(otmp, Blind ? "vibrate" : "glow"),
186		Blind ? "" : " ",
187		Blind ? nul : hcolor(color));
188}
189
190/* Is the object chargeable?  For purposes of inventory display; it is */
191/* possible to be able to charge things for which this returns FALSE. */
192boolean
193is_chargeable(obj)
194struct obj *obj;
195{
196	if (obj->oclass == WAND_CLASS) return TRUE;
197	/* known && !uname is possible after amnesia/mind flayer */
198	if (obj->oclass == RING_CLASS)
199	    return (boolean)(objects[obj->otyp].oc_charged &&
200			(obj->known || objects[obj->otyp].oc_uname));
201	if (is_weptool(obj))	/* specific check before general tools */
202	    return FALSE;
203	if (obj->oclass == TOOL_CLASS)
204	    return (boolean)(objects[obj->otyp].oc_charged);
205	return FALSE; /* why are weapons/armor considered charged anyway? */
206}
207
208/*
209 * recharge an object; curse_bless is -1 if the recharging implement
210 * was cursed, +1 if blessed, 0 otherwise.
211 */
212void
213recharge(obj, curse_bless)
214struct obj *obj;
215int curse_bless;
216{
217	register int n;
218	boolean is_cursed, is_blessed;
219
220	is_cursed = curse_bless < 0;
221	is_blessed = curse_bless > 0;
222
223	if (obj->oclass == WAND_CLASS) {
224	    /* undo any prior cancellation, even when is_cursed */
225	    if (obj->spe == -1) obj->spe = 0;
226
227	    /*
228	     * Recharging might cause wands to explode.
229	     *	v = number of previous recharges
230	     *	      v = percentage chance to explode on this attempt
231	     *		      v = cumulative odds for exploding
232	     *	0 :   0       0
233	     *	1 :   0.29    0.29
234	     *	2 :   2.33    2.62
235	     *	3 :   7.87   10.28
236	     *	4 :  18.66   27.02
237	     *	5 :  36.44   53.62
238	     *	6 :  62.97   82.83
239	     *	7 : 100     100
240	     */
241	    n = (int)obj->recharged;
242	    if (n > 0 && (obj->otyp == WAN_WISHING ||
243		    (n * n * n > rn2(7*7*7)))) {	/* recharge_limit */
244		wand_explode(obj);
245		return;
246	    }
247	    /* didn't explode, so increment the recharge count */
248	    obj->recharged = (unsigned)(n + 1);
249
250	    /* now handle the actual recharging */
251	    if (is_cursed) {
252		stripspe(obj);
253	    } else {
254		int lim = (obj->otyp == WAN_WISHING) ? 3 :
255			(objects[obj->otyp].oc_dir != NODIR) ? 8 : 15;
256
257		n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5);
258		if (!is_blessed) n = rnd(n);
259
260		if (obj->spe < n) obj->spe = n;
261		else obj->spe++;
262		if (obj->otyp == WAN_WISHING && obj->spe > 3) {
263		    wand_explode(obj);
264		    return;
265		}
266		if (obj->spe >= lim) p_glow2(obj, NH_BLUE);
267		else p_glow1(obj);
268	    }
269
270	} else if (obj->oclass == RING_CLASS &&
271					objects[obj->otyp].oc_charged) {
272	    /* charging does not affect ring's curse/bless status */
273	    int s = is_blessed ? rnd(3) : is_cursed ? -rnd(2) : 1;
274	    boolean is_on = (obj == uleft || obj == uright);
275
276	    /* destruction depends on current state, not adjustment */
277	    if (obj->spe > rn2(7) || obj->spe <= -5) {
278		Your("%s %s momentarily, then %s!",
279		     xname(obj), otense(obj,"pulsate"), otense(obj,"explode"));
280		if (is_on) Ring_gone(obj);
281		s = rnd(3 * abs(obj->spe));	/* amount of damage */
282		useup(obj);
283		losehp(s, "exploding ring", KILLED_BY_AN);
284	    } else {
285		long mask = is_on ? (obj == uleft ? LEFT_RING :
286				     RIGHT_RING) : 0L;
287		Your("%s spins %sclockwise for a moment.",
288		     xname(obj), s < 0 ? "counter" : "");
289		/* cause attributes and/or properties to be updated */
290		if (is_on) Ring_off(obj);
291		obj->spe += s;	/* update the ring while it's off */
292		if (is_on) setworn(obj, mask), Ring_on(obj);
293		/* oartifact: if a touch-sensitive artifact ring is
294		   ever created the above will need to be revised  */
295	    }
296
297	} else if (obj->oclass == TOOL_CLASS) {
298	    int rechrg = (int)obj->recharged;
299
300	    if (objects[obj->otyp].oc_charged) {
301		/* tools don't have a limit, but the counter used does */
302		if (rechrg < 7)	/* recharge_limit */
303		    obj->recharged++;
304	    }
305	    switch(obj->otyp) {
306	    case BELL_OF_OPENING:
307		if (is_cursed) stripspe(obj);
308		else if (is_blessed) obj->spe += rnd(3);
309		else obj->spe += 1;
310		if (obj->spe > 5) obj->spe = 5;
311		break;
312	    case MAGIC_MARKER:
313	    case TINNING_KIT:
314#ifdef TOURIST
315	    case EXPENSIVE_CAMERA:
316#endif
317		if (is_cursed) stripspe(obj);
318		else if (rechrg && obj->otyp == MAGIC_MARKER) {	/* previously recharged */
319		    obj->recharged = 1;	/* override increment done above */
320		    if (obj->spe < 3)
321			Your("marker seems permanently dried out.");
322		    else
323			pline(nothing_happens);
324		} else if (is_blessed) {
325		    n = rn1(16,15);		/* 15..30 */
326		    if (obj->spe + n <= 50)
327			obj->spe = 50;
328		    else if (obj->spe + n <= 75)
329			obj->spe = 75;
330		    else {
331			int chrg = (int)obj->spe;
332			if ((chrg + n) > 127)
333				obj->spe = 127;
334			else
335				obj->spe += n;
336		    }
337		    p_glow2(obj, NH_BLUE);
338		} else {
339		    n = rn1(11,10);		/* 10..20 */
340		    if (obj->spe + n <= 50)
341			obj->spe = 50;
342		    else {
343			int chrg = (int)obj->spe;
344			if ((chrg + n) > 127)
345				obj->spe = 127;
346			else
347				obj->spe += n;
348		    }
349		    p_glow2(obj, NH_WHITE);
350		}
351		break;
352	    case OIL_LAMP:
353	    case BRASS_LANTERN:
354		if (is_cursed) {
355		    stripspe(obj);
356		    if (obj->lamplit) {
357			if (!Blind)
358			    pline("%s out!", Tobjnam(obj, "go"));
359			end_burn(obj, TRUE);
360		    }
361		} else if (is_blessed) {
362		    obj->spe = 1;
363		    obj->age = 1500;
364		    p_glow2(obj, NH_BLUE);
365		} else {
366		    obj->spe = 1;
367		    obj->age += 750;
368		    if (obj->age > 1500) obj->age = 1500;
369		    p_glow1(obj);
370		}
371		break;
372	    case CRYSTAL_BALL:
373		if (is_cursed) stripspe(obj);
374		else if (is_blessed) {
375		    obj->spe = 6;
376		    p_glow2(obj, NH_BLUE);
377		} else {
378		    if (obj->spe < 5) {
379			obj->spe++;
380			p_glow1(obj);
381		    } else pline(nothing_happens);
382		}
383		break;
384	    case HORN_OF_PLENTY:
385	    case BAG_OF_TRICKS:
386	    case CAN_OF_GREASE:
387		if (is_cursed) stripspe(obj);
388		else if (is_blessed) {
389		    if (obj->spe <= 10)
390			obj->spe += rn1(10, 6);
391		    else obj->spe += rn1(5, 6);
392		    if (obj->spe > 50) obj->spe = 50;
393		    p_glow2(obj, NH_BLUE);
394		} else {
395		    obj->spe += rnd(5);
396		    if (obj->spe > 50) obj->spe = 50;
397		    p_glow1(obj);
398		}
399		break;
400	    case MAGIC_FLUTE:
401	    case MAGIC_HARP:
402	    case FROST_HORN:
403	    case FIRE_HORN:
404	    case DRUM_OF_EARTHQUAKE:
405		if (is_cursed) {
406		    stripspe(obj);
407		} else if (is_blessed) {
408		    obj->spe += d(2,4);
409		    if (obj->spe > 20) obj->spe = 20;
410		    p_glow2(obj, NH_BLUE);
411		} else {
412		    obj->spe += rnd(4);
413		    if (obj->spe > 20) obj->spe = 20;
414		    p_glow1(obj);
415		}
416		break;
417	    default:
418		goto not_chargable;
419		/*NOTREACHED*/
420		break;
421	    } /* switch */
422
423	} else {
424 not_chargable:
425	    You("have a feeling of loss.");
426	}
427}
428
429
430/* Forget known information about this object class. */
431static void
432forget_single_object(obj_id)
433	int obj_id;
434{
435	objects[obj_id].oc_name_known = 0;
436	objects[obj_id].oc_pre_discovered = 0;	/* a discovery when relearned */
437	if (objects[obj_id].oc_uname) {
438	    free((genericptr_t)objects[obj_id].oc_uname);
439	    objects[obj_id].oc_uname = 0;
440	}
441	undiscover_object(obj_id);	/* after clearing oc_name_known */
442
443	/* clear & free object names from matching inventory items too? */
444}
445
446
447#if 0	/* here if anyone wants it.... */
448/* Forget everything known about a particular object class. */
449static void
450forget_objclass(oclass)
451	int oclass;
452{
453	int i;
454
455	for (i=bases[oclass];
456		i < NUM_OBJECTS && objects[i].oc_class==oclass; i++)
457	    forget_single_object(i);
458}
459#endif
460
461
462/* randomize the given list of numbers  0 <= i < count */
463static void
464randomize(indices, count)
465	int *indices;
466	int count;
467{
468	int i, iswap, temp;
469
470	for (i = count - 1; i > 0; i--) {
471	    if ((iswap = rn2(i + 1)) == i) continue;
472	    temp = indices[i];
473	    indices[i] = indices[iswap];
474	    indices[iswap] = temp;
475	}
476}
477
478
479/* Forget % of known objects. */
480void
481forget_objects(percent)
482	int percent;
483{
484	int i, count;
485	int indices[NUM_OBJECTS];
486
487	if (percent == 0) return;
488	if (percent <= 0 || percent > 100) {
489	    impossible("forget_objects: bad percent %d", percent);
490	    return;
491	}
492
493	for (count = 0, i = 1; i < NUM_OBJECTS; i++)
494	    if (OBJ_DESCR(objects[i]) &&
495		    (objects[i].oc_name_known || objects[i].oc_uname))
496		indices[count++] = i;
497
498	randomize(indices, count);
499
500	/* forget first % of randomized indices */
501	count = ((count * percent) + 50) / 100;
502	for (i = 0; i < count; i++)
503	    forget_single_object(indices[i]);
504}
505
506
507/* Forget some or all of map (depends on parameters). */
508void
509forget_map(howmuch)
510	int howmuch;
511{
512	register int zx, zy;
513
514	if (In_sokoban(&u.uz))
515	    return;
516
517	known = TRUE;
518	for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++)
519	    if (howmuch & ALL_MAP || rn2(7)) {
520		/* Zonk all memory of this location. */
521		levl[zx][zy].seenv = 0;
522		levl[zx][zy].waslit = 0;
523		levl[zx][zy].glyph = cmap_to_glyph(S_stone);
524	    }
525}
526
527/* Forget all traps on the level. */
528void
529forget_traps()
530{
531	register struct trap *trap;
532
533	/* forget all traps (except the one the hero is in :-) */
534	for (trap = ftrap; trap; trap = trap->ntrap)
535	    if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE))
536		trap->tseen = 0;
537}
538
539/*
540 * Forget given % of all levels that the hero has visited and not forgotten,
541 * except this one.
542 */
543void
544forget_levels(percent)
545	int percent;
546{
547	int i, count;
548	xchar  maxl, this_lev;
549	int indices[MAXLINFO];
550
551	if (percent == 0) return;
552
553	if (percent <= 0 || percent > 100) {
554	    impossible("forget_levels: bad percent %d", percent);
555	    return;
556	}
557
558	this_lev = ledger_no(&u.uz);
559	maxl = maxledgerno();
560
561	/* count & save indices of non-forgotten visited levels */
562	/* Sokoban levels are pre-mapped for the player, and should stay
563	 * so, or they become nearly impossible to solve.  But try to
564	 * shift the forgetting elsewhere by fiddling with percent
565	 * instead of forgetting fewer levels.
566	 */
567	for (count = 0, i = 0; i <= maxl; i++)
568	    if ((level_info[i].flags & VISITED) &&
569			!(level_info[i].flags & FORGOTTEN) && i != this_lev) {
570		if (ledger_to_dnum(i) == sokoban_dnum)
571		    percent += 2;
572		else
573		    indices[count++] = i;
574	    }
575
576	if (percent > 100) percent = 100;
577
578	randomize(indices, count);
579
580	/* forget first % of randomized indices */
581	count = ((count * percent) + 50) / 100;
582	for (i = 0; i < count; i++) {
583	    level_info[indices[i]].flags |= FORGOTTEN;
584	}
585}
586
587/*
588 * Forget some things (e.g. after reading a scroll of amnesia).  When called,
589 * the following are always forgotten:
590 *
591 *	- felt ball & chain
592 *	- traps
593 *	- part (6 out of 7) of the map
594 *
595 * Other things are subject to flags:
596 *
597 *	howmuch & ALL_MAP	= forget whole map
598 *	howmuch & ALL_SPELLS	= forget all spells
599 */
600static void
601forget(howmuch)
602int howmuch;
603{
604
605	if (Punished) u.bc_felt = 0;	/* forget felt ball&chain */
606
607	forget_map(howmuch);
608	forget_traps();
609
610	/* 1 in 3 chance of forgetting some levels */
611	if (!rn2(3)) forget_levels(rn2(25));
612
613	/* 1 in 3 chance of forgeting some objects */
614	if (!rn2(3)) forget_objects(rn2(25));
615
616	if (howmuch & ALL_SPELLS) losespells();
617	/*
618	 * Make sure that what was seen is restored correctly.  To do this,
619	 * we need to go blind for an instant --- turn off the display,
620	 * then restart it.  All this work is needed to correctly handle
621	 * walls which are stone on one side and wall on the other.  Turning
622	 * off the seen bits above will make the wall revert to stone,  but
623	 * there are cases where we don't want this to happen.  The easiest
624	 * thing to do is to run it through the vision system again, which
625	 * is always correct.
626	 */
627	docrt();		/* this correctly will reset vision */
628}
629
630/* monster is hit by scroll of taming's effect */
631static void
632maybe_tame(mtmp, sobj)
633struct monst *mtmp;
634struct obj *sobj;
635{
636	if (sobj->cursed) {
637	    setmangry(mtmp);
638	} else {
639	    if (mtmp->isshk)
640		make_happy_shk(mtmp, FALSE);
641	    else if (!resist(mtmp, sobj->oclass, 0, NOTELL))
642		(void) tamedog(mtmp, (struct obj *) 0);
643	}
644}
645
646int
647seffects(sobj)
648register struct obj	*sobj;
649{
650	register int cval;
651	register boolean confused = (Confusion != 0);
652	register struct obj *otmp;
653
654	if (objects[sobj->otyp].oc_magic)
655		exercise(A_WIS, TRUE);		/* just for trying */
656	switch(sobj->otyp) {
657#ifdef MAIL
658	case SCR_MAIL:
659		known = TRUE;
660		if (sobj->spe)
661		    pline("This seems to be junk mail addressed to the finder of the Eye of Larn.");
662		/* note to the puzzled: the game Larn actually sends you junk
663		 * mail if you win!
664		 */
665		else readmail(sobj);
666		break;
667#endif
668	case SCR_ENCHANT_ARMOR:
669	    {
670		register schar s;
671		boolean special_armor;
672		boolean same_color;
673
674		otmp = some_armor(&youmonst);
675		if(!otmp) {
676			strange_feeling(sobj,
677					!Blind ? "Your skin glows then fades." :
678					"Your skin feels warm for a moment.");
679			exercise(A_CON, !sobj->cursed);
680			exercise(A_STR, !sobj->cursed);
681			return(1);
682		}
683		if(confused) {
684			otmp->oerodeproof = !(sobj->cursed);
685			if(Blind) {
686			    otmp->rknown = FALSE;
687			    Your("%s %s warm for a moment.",
688				xname(otmp), otense(otmp, "feel"));
689			} else {
690			    otmp->rknown = TRUE;
691			    Your("%s %s covered by a %s %s %s!",
692				xname(otmp), otense(otmp, "are"),
693				sobj->cursed ? "mottled" : "shimmering",
694				 hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN),
695				sobj->cursed ? "glow" :
696				  (is_shield(otmp) ? "layer" : "shield"));
697			}
698			if (otmp->oerodeproof &&
699			    (otmp->oeroded || otmp->oeroded2)) {
700			    otmp->oeroded = otmp->oeroded2 = 0;
701			    Your("%s %s as good as new!",
702				 xname(otmp),
703				 otense(otmp, Blind ? "feel" : "look"));
704			}
705			break;
706		}
707		/* elven armor vibrates warningly when enchanted beyond a limit */
708		special_armor = is_elven_armor(otmp) ||
709			(Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM);
710		if (sobj->cursed)
711		    same_color =
712			(otmp->otyp == BLACK_DRAGON_SCALE_MAIL ||
713			 otmp->otyp == BLACK_DRAGON_SCALES);
714		else
715		    same_color =
716			(otmp->otyp == SILVER_DRAGON_SCALE_MAIL ||
717			 otmp->otyp == SILVER_DRAGON_SCALES ||
718			 otmp->otyp == SHIELD_OF_REFLECTION);
719		if (Blind) same_color = FALSE;
720
721		/* KMH -- catch underflow */
722		s = sobj->cursed ? -otmp->spe : otmp->spe;
723		if (s > (special_armor ? 5 : 3) && rn2(s)) {
724		Your("%s violently %s%s%s for a while, then %s.",
725		     xname(otmp),
726		     otense(otmp, Blind ? "vibrate" : "glow"),
727		     (!Blind && !same_color) ? " " : nul,
728		     (Blind || same_color) ? nul :
729			hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
730		     otense(otmp, "evaporate"));
731			if(is_cloak(otmp)) (void) Cloak_off();
732			if(is_boots(otmp)) (void) Boots_off();
733			if(is_helmet(otmp)) (void) Helmet_off();
734			if(is_gloves(otmp)) (void) Gloves_off();
735			if(is_shield(otmp)) (void) Shield_off();
736			if(otmp == uarm) (void) Armor_gone();
737			useup(otmp);
738			break;
739		}
740		s = sobj->cursed ? -1 :
741		    otmp->spe >= 9 ? (rn2(otmp->spe) == 0) :
742		    sobj->blessed ? rnd(3-otmp->spe/3) : 1;
743		if (s >= 0 && otmp->otyp >= GRAY_DRAGON_SCALES &&
744					otmp->otyp <= YELLOW_DRAGON_SCALES) {
745			/* dragon scales get turned into dragon scale mail */
746			Your("%s merges and hardens!", xname(otmp));
747			setworn((struct obj *)0, W_ARM);
748			/* assumes same order */
749			otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
750						otmp->otyp - GRAY_DRAGON_SCALES;
751			otmp->cursed = 0;
752			if (sobj->blessed) {
753				otmp->spe++;
754				otmp->blessed = 1;
755			}
756			otmp->known = 1;
757			setworn(otmp, W_ARM);
758			break;
759		}
760		Your("%s %s%s%s%s for a %s.",
761			xname(otmp),
762		        s == 0 ? "violently " : nul,
763			otense(otmp, Blind ? "vibrate" : "glow"),
764			(!Blind && !same_color) ? " " : nul,
765			(Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
766			  (s*s>1) ? "while" : "moment");
767		otmp->cursed = sobj->cursed;
768		if (!otmp->blessed || sobj->cursed)
769			otmp->blessed = sobj->blessed;
770		if (s) {
771			otmp->spe += s;
772			adj_abon(otmp, s);
773			known = otmp->known;
774		}
775
776		if ((otmp->spe > (special_armor ? 5 : 3)) &&
777		    (special_armor || !rn2(7)))
778			Your("%s suddenly %s %s.",
779				xname(otmp), otense(otmp, "vibrate"),
780				Blind ? "again" : "unexpectedly");
781		break;
782	    }
783	case SCR_DESTROY_ARMOR:
784	    {
785		otmp = some_armor(&youmonst);
786		if(confused) {
787			if(!otmp) {
788				strange_feeling(sobj,"Your bones itch.");
789				exercise(A_STR, FALSE);
790				exercise(A_CON, FALSE);
791				return(1);
792			}
793			otmp->oerodeproof = sobj->cursed;
794			p_glow2(otmp, NH_PURPLE);
795			break;
796		}
797		if(!sobj->cursed || !otmp || !otmp->cursed) {
798		    if(!destroy_arm(otmp)) {
799			strange_feeling(sobj,"Your skin itches.");
800			exercise(A_STR, FALSE);
801			exercise(A_CON, FALSE);
802			return(1);
803		    } else
804			known = TRUE;
805		} else {	/* armor and scroll both cursed */
806		    Your("%s %s.", xname(otmp), otense(otmp, "vibrate"));
807		    if (otmp->spe >= -6) otmp->spe--;
808		    make_stunned(HStun + rn1(10, 10), TRUE);
809		}
810	    }
811	    break;
812	case SCR_CONFUSE_MONSTER:
813	case SPE_CONFUSE_MONSTER:
814		if(youmonst.data->mlet != S_HUMAN || sobj->cursed) {
815			if(!HConfusion) You_feel("confused.");
816			make_confused(HConfusion + rnd(100),FALSE);
817		} else  if(confused) {
818		    if(!sobj->blessed) {
819			Your("%s begin to %s%s.",
820			    makeplural(body_part(HAND)),
821			    Blind ? "tingle" : "glow ",
822			    Blind ? nul : hcolor(NH_PURPLE));
823			make_confused(HConfusion + rnd(100),FALSE);
824		    } else {
825			pline("A %s%s surrounds your %s.",
826			    Blind ? nul : hcolor(NH_RED),
827			    Blind ? "faint buzz" : " glow",
828			    body_part(HEAD));
829			make_confused(0L,TRUE);
830		    }
831		} else {
832		    if (!sobj->blessed) {
833			Your("%s%s %s%s.",
834			makeplural(body_part(HAND)),
835			Blind ? "" : " begin to glow",
836			Blind ? (const char *)"tingle" : hcolor(NH_RED),
837			u.umconf ? " even more" : "");
838			u.umconf++;
839		    } else {
840			if (Blind)
841			    Your("%s tingle %s sharply.",
842				makeplural(body_part(HAND)),
843				u.umconf ? "even more" : "very");
844			else
845			    Your("%s glow a%s brilliant %s.",
846				makeplural(body_part(HAND)),
847				u.umconf ? "n even more" : "",
848				hcolor(NH_RED));
849			/* after a while, repeated uses become less effective */
850			if (u.umconf >= 40)
851			    u.umconf++;
852			else
853			    u.umconf += rn1(8, 2);
854		    }
855		}
856		break;
857	case SCR_SCARE_MONSTER:
858	case SPE_CAUSE_FEAR:
859	    {	register int ct = 0;
860		register struct monst *mtmp;
861
862		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
863		    if (DEADMONSTER(mtmp)) continue;
864		    if(cansee(mtmp->mx,mtmp->my)) {
865			if(confused || sobj->cursed) {
866			    mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0;
867			    mtmp->mcanmove = 1;
868			} else
869			    if (! resist(mtmp, sobj->oclass, 0, NOTELL))
870				monflee(mtmp, 0, FALSE, FALSE);
871			if(!mtmp->mtame) ct++;	/* pets don't laugh at you */
872		    }
873		}
874		if(!ct)
875		      You_hear("%s in the distance.",
876			       (confused || sobj->cursed) ? "sad wailing" :
877							"maniacal laughter");
878		else if(sobj->otyp == SCR_SCARE_MONSTER)
879			You_hear("%s close by.",
880				  (confused || sobj->cursed) ? "sad wailing" :
881						 "maniacal laughter");
882		break;
883	    }
884	case SCR_BLANK_PAPER:
885	    if (Blind)
886		You("don't remember there being any magic words on this scroll.");
887	    else
888		pline("This scroll seems to be blank.");
889	    known = TRUE;
890	    break;
891	case SCR_REMOVE_CURSE:
892	case SPE_REMOVE_CURSE:
893	    {	register struct obj *obj;
894		if(confused)
895		    if (Hallucination)
896			You_feel("the power of the Force against you!");
897		    else
898			You_feel("like you need some help.");
899		else
900		    if (Hallucination)
901			You_feel("in touch with the Universal Oneness.");
902		    else
903			You_feel("like someone is helping you.");
904
905		if (sobj->cursed) {
906		    pline_The("scroll disintegrates.");
907		} else {
908		    for (obj = invent; obj; obj = obj->nobj) {
909			long wornmask;
910#ifdef GOLDOBJ
911			/* gold isn't subject to cursing and blessing */
912			if (obj->oclass == COIN_CLASS) continue;
913#endif
914			wornmask = (obj->owornmask & ~(W_BALL|W_ART|W_ARTI));
915			if (wornmask && !sobj->blessed) {
916			    /* handle a couple of special cases; we don't
917			       allow auxiliary weapon slots to be used to
918			       artificially increase number of worn items */
919			    if (obj == uswapwep) {
920				if (!u.twoweap) wornmask = 0L;
921			    } else if (obj == uquiver) {
922				if (obj->oclass == WEAPON_CLASS) {
923				    /* mergeable weapon test covers ammo,
924				       missiles, spears, daggers & knives */
925				    if (!objects[obj->otyp].oc_merge)
926					wornmask = 0L;
927				} else if (obj->oclass == GEM_CLASS) {
928				    /* possibly ought to check whether
929				       alternate weapon is a sling... */
930				    if (!uslinging()) wornmask = 0L;
931				} else {
932				    /* weptools don't merge and aren't
933				       reasonable quivered weapons */
934				    wornmask = 0L;
935				}
936			    }
937			}
938			if (sobj->blessed || wornmask ||
939			     obj->otyp == LOADSTONE ||
940			     (obj->otyp == LEASH && obj->leashmon)) {
941			    if(confused) blessorcurse(obj, 2);
942			    else uncurse(obj);
943			}
944		    }
945		}
946		if(Punished && !confused) unpunish();
947		update_inventory();
948		break;
949	    }
950	case SCR_CREATE_MONSTER:
951	case SPE_CREATE_MONSTER:
952	    if (create_critters(1 + ((confused || sobj->cursed) ? 12 : 0) +
953				((sobj->blessed || rn2(73)) ? 0 : rnd(4)),
954			confused ? &mons[PM_ACID_BLOB] : (struct permonst *)0))
955		known = TRUE;
956	    /* no need to flush monsters; we ask for identification only if the
957	     * monsters are not visible
958	     */
959	    break;
960	case SCR_ENCHANT_WEAPON:
961		if(uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))
962			&& confused) {
963		/* oclass check added 10/25/86 GAN */
964			uwep->oerodeproof = !(sobj->cursed);
965			if (Blind) {
966			    uwep->rknown = FALSE;
967			    Your("weapon feels warm for a moment.");
968			} else {
969			    uwep->rknown = TRUE;
970			    Your("%s covered by a %s %s %s!",
971				aobjnam(uwep, "are"),
972				sobj->cursed ? "mottled" : "shimmering",
973				hcolor(sobj->cursed ? NH_PURPLE : NH_GOLDEN),
974				sobj->cursed ? "glow" : "shield");
975			}
976			if (uwep->oerodeproof && (uwep->oeroded || uwep->oeroded2)) {
977			    uwep->oeroded = uwep->oeroded2 = 0;
978			    Your("%s as good as new!",
979				 aobjnam(uwep, Blind ? "feel" : "look"));
980			}
981		} else return !chwepon(sobj,
982				       sobj->cursed ? -1 :
983				       !uwep ? 1 :
984				       uwep->spe >= 9 ? (rn2(uwep->spe) == 0) :
985				       sobj->blessed ? rnd(3-uwep->spe/3) : 1);
986		break;
987	case SCR_TAMING:
988	case SPE_CHARM_MONSTER:
989		if (u.uswallow) {
990		    maybe_tame(u.ustuck, sobj);
991		} else {
992		    int i, j, bd = confused ? 5 : 1;
993		    struct monst *mtmp;
994
995		    for (i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++) {
996			if (!isok(u.ux + i, u.uy + j)) continue;
997			if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0)
998			    maybe_tame(mtmp, sobj);
999		    }
1000		}
1001		break;
1002	case SCR_GENOCIDE:
1003		You("have found a scroll of genocide!");
1004		known = TRUE;
1005		if (sobj->blessed) do_class_genocide();
1006		else do_genocide(!sobj->cursed | (2 * !!Confusion));
1007		break;
1008	case SCR_LIGHT:
1009		if(!Blind) known = TRUE;
1010		litroom(!confused && !sobj->cursed, sobj);
1011		break;
1012	case SCR_TELEPORTATION:
1013		if(confused || sobj->cursed) level_tele();
1014		else {
1015			if (sobj->blessed && !Teleport_control) {
1016				known = TRUE;
1017				if (yn("Do you wish to teleport?")=='n')
1018					break;
1019			}
1020			tele();
1021			if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
1022			   (distu(u.ux0, u.uy0) >= 16))
1023				known = TRUE;
1024		}
1025		break;
1026	case SCR_GOLD_DETECTION:
1027		if (confused || sobj->cursed) return(trap_detect(sobj));
1028		else return(gold_detect(sobj));
1029	case SCR_FOOD_DETECTION:
1030	case SPE_DETECT_FOOD:
1031		if (food_detect(sobj))
1032			return(1);	/* nothing detected */
1033		break;
1034	case SPE_IDENTIFY:
1035		cval = rn2(5);
1036		goto id;
1037	case SCR_IDENTIFY:
1038		/* known = TRUE; */
1039		if(confused)
1040			You("identify this as an identify scroll.");
1041		else
1042			pline("This is an identify scroll.");
1043		if (sobj->blessed || (!sobj->cursed && !rn2(5))) {
1044			cval = rn2(5);
1045			/* Note: if rn2(5)==0, identify all items */
1046			if (cval == 1 && sobj->blessed && Luck > 0) ++cval;
1047		} else	cval = 1;
1048		if(!objects[sobj->otyp].oc_name_known) more_experienced(0,10);
1049		useup(sobj);
1050		makeknown(SCR_IDENTIFY);
1051	id:
1052		if(invent && !confused) {
1053		    identify_pack(cval);
1054		}
1055		return(1);
1056	case SCR_CHARGING:
1057		if (confused) {
1058		    You_feel("charged up!");
1059		    if (u.uen < u.uenmax)
1060			u.uen = u.uenmax;
1061		    else
1062			u.uen = (u.uenmax += d(5,4));
1063		    flags.botl = 1;
1064		    break;
1065		}
1066		known = TRUE;
1067		pline("This is a charging scroll.");
1068		otmp = getobj(all_count, "charge");
1069		if (!otmp) break;
1070		recharge(otmp, sobj->cursed ? -1 : (sobj->blessed ? 1 : 0));
1071		break;
1072	case SCR_MAGIC_MAPPING:
1073		if (level.flags.nommap) {
1074		    Your("mind is filled with crazy lines!");
1075		    if (Hallucination)
1076			pline("Wow!  Modern art.");
1077		    else
1078			Your("%s spins in bewilderment.", body_part(HEAD));
1079		    make_confused(HConfusion + rnd(30), FALSE);
1080		    break;
1081		}
1082		if (sobj->blessed) {
1083		    register int x, y;
1084
1085		    for (x = 1; x < COLNO; x++)
1086		    	for (y = 0; y < ROWNO; y++)
1087		    	    if (levl[x][y].typ == SDOOR)
1088		    	    	cvt_sdoor_to_door(&levl[x][y]);
1089		    /* do_mapping() already reveals secret passages */
1090		}
1091		known = TRUE;
1092	case SPE_MAGIC_MAPPING:
1093		if (level.flags.nommap) {
1094		    Your("%s spins as %s blocks the spell!", body_part(HEAD), something);
1095		    make_confused(HConfusion + rnd(30), FALSE);
1096		    break;
1097		}
1098		pline("A map coalesces in your mind!");
1099		cval = (sobj->cursed && !confused);
1100		if(cval) HConfusion = 1;	/* to screw up map */
1101		do_mapping();
1102		if(cval) {
1103		    HConfusion = 0;		/* restore */
1104		    pline("Unfortunately, you can't grasp the details.");
1105		}
1106		break;
1107	case SCR_AMNESIA:
1108		known = TRUE;
1109		forget(	(!sobj->blessed ? ALL_SPELLS : 0) |
1110			(!confused || sobj->cursed ? ALL_MAP : 0) );
1111		if (Hallucination) /* Ommmmmm! */
1112			Your("mind releases itself from mundane concerns.");
1113		else if (!strncmpi(plname, "Maud", 4))
1114			pline("As your mind turns inward on itself, you forget everything else.");
1115		else if (rn2(2))
1116			pline("Who was that Maud person anyway?");
1117		else
1118			pline("Thinking of Maud you forget everything else.");
1119		exercise(A_WIS, FALSE);
1120		break;
1121	case SCR_FIRE:
1122		/*
1123		 * Note: Modifications have been made as of 3.0 to allow for
1124		 * some damage under all potential cases.
1125		 */
1126		cval = bcsign(sobj);
1127		if(!objects[sobj->otyp].oc_name_known) more_experienced(0,10);
1128		useup(sobj);
1129		makeknown(SCR_FIRE);
1130		if(confused) {
1131		    if(Fire_resistance) {
1132			shieldeff(u.ux, u.uy);
1133			if(!Blind)
1134			    pline("Oh, look, what a pretty fire in your %s.",
1135				makeplural(body_part(HAND)));
1136			else You_feel("a pleasant warmth in your %s.",
1137				makeplural(body_part(HAND)));
1138		    } else {
1139			pline_The("scroll catches fire and you burn your %s.",
1140				makeplural(body_part(HAND)));
1141			losehp(1, "scroll of fire", KILLED_BY_AN);
1142		    }
1143		    return(1);
1144		}
1145		if (Underwater)
1146			pline_The("water around you vaporizes violently!");
1147		else {
1148		    pline_The("scroll erupts in a tower of flame!");
1149		    burn_away_slime();
1150		}
1151		explode(u.ux, u.uy, 11, (2*(rn1(3, 3) + 2 * cval) + 1)/3,
1152							SCROLL_CLASS, EXPL_FIERY);
1153		return(1);
1154	case SCR_EARTH:
1155	    /* TODO: handle steeds */
1156	    if (
1157#ifdef REINCARNATION
1158		!Is_rogue_level(&u.uz) &&
1159#endif
1160	    	 (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
1161	    	register int x, y;
1162
1163	    	/* Identify the scroll */
1164	    	pline_The("%s rumbles %s you!", ceiling(u.ux,u.uy),
1165	    			sobj->blessed ? "around" : "above");
1166	    	known = 1;
1167	    	if (In_sokoban(&u.uz))
1168	    	    change_luck(-1);	/* Sokoban guilt */
1169
1170	    	/* Loop through the surrounding squares */
1171	    	if (!sobj->cursed) for (x = u.ux-1; x <= u.ux+1; x++) {
1172	    	    for (y = u.uy-1; y <= u.uy+1; y++) {
1173
1174	    	    	/* Is this a suitable spot? */
1175	    	    	if (isok(x, y) && !closed_door(x, y) &&
1176	    	    			!IS_ROCK(levl[x][y].typ) &&
1177	    	    			!IS_AIR(levl[x][y].typ) &&
1178					(x != u.ux || y != u.uy)) {
1179			    register struct obj *otmp2;
1180			    register struct monst *mtmp;
1181
1182	    	    	    /* Make the object(s) */
1183	    	    	    otmp2 = mksobj(confused ? ROCK : BOULDER,
1184	    	    	    		FALSE, FALSE);
1185	    	    	    if (!otmp2) continue;  /* Shouldn't happen */
1186	    	    	    otmp2->quan = confused ? rn1(5,2) : 1;
1187	    	    	    otmp2->owt = weight(otmp2);
1188
1189	    	    	    /* Find the monster here (won't be player) */
1190	    	    	    mtmp = m_at(x, y);
1191	    	    	    if (mtmp && !amorphous(mtmp->data) &&
1192	    	    	    		!passes_walls(mtmp->data) &&
1193	    	    	    		!noncorporeal(mtmp->data) &&
1194	    	    	    		!unsolid(mtmp->data)) {
1195				struct obj *helmet = which_armor(mtmp, W_ARMH);
1196				int mdmg;
1197
1198				if (cansee(mtmp->mx, mtmp->my)) {
1199				    pline("%s is hit by %s!", Monnam(mtmp),
1200	    	    	    			doname(otmp2));
1201				    if (mtmp->minvis && !canspotmon(mtmp))
1202					map_invisible(mtmp->mx, mtmp->my);
1203				}
1204	    	    	    	mdmg = dmgval(otmp2, mtmp) * otmp2->quan;
1205				if (helmet) {
1206				    if(is_metallic(helmet)) {
1207					if (canspotmon(mtmp))
1208					    pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp));
1209					else if (flags.soundok)
1210					    You_hear("a clanging sound.");
1211					if (mdmg > 2) mdmg = 2;
1212				    } else {
1213					if (canspotmon(mtmp))
1214					    pline("%s's %s does not protect %s.",
1215						Monnam(mtmp), xname(helmet),
1216						mhim(mtmp));
1217				    }
1218				}
1219	    	    	    	mtmp->mhp -= mdmg;
1220	    	    	    	if (mtmp->mhp <= 0)
1221	    	    	    	    xkilled(mtmp, 1);
1222	    	    	    }
1223	    	    	    /* Drop the rock/boulder to the floor */
1224	    	    	    if (!flooreffects(otmp2, x, y, "fall")) {
1225	    	    	    	place_object(otmp2, x, y);
1226	    	    	    	stackobj(otmp2);
1227	    	    	    	newsym(x, y);  /* map the rock */
1228	    	    	    }
1229	    	    	}
1230		    }
1231		}
1232		/* Attack the player */
1233		if (!sobj->blessed) {
1234		    int dmg;
1235		    struct obj *otmp2;
1236
1237		    /* Okay, _you_ write this without repeating the code */
1238		    otmp2 = mksobj(confused ? ROCK : BOULDER,
1239				FALSE, FALSE);
1240		    if (!otmp2) break;
1241		    otmp2->quan = confused ? rn1(5,2) : 1;
1242		    otmp2->owt = weight(otmp2);
1243		    if (!amorphous(youmonst.data) &&
1244				!Passes_walls &&
1245				!noncorporeal(youmonst.data) &&
1246				!unsolid(youmonst.data)) {
1247			You("are hit by %s!", doname(otmp2));
1248			dmg = dmgval(otmp2, &youmonst) * otmp2->quan;
1249			if (uarmh && !sobj->cursed) {
1250			    if(is_metallic(uarmh)) {
1251				pline("Fortunately, you are wearing a hard helmet.");
1252				if (dmg > 2) dmg = 2;
1253			    } else if (flags.verbose) {
1254				Your("%s does not protect you.",
1255						xname(uarmh));
1256			    }
1257			}
1258		    } else
1259			dmg = 0;
1260		    /* Must be before the losehp(), for bones files */
1261		    if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
1262			place_object(otmp2, u.ux, u.uy);
1263			stackobj(otmp2);
1264			newsym(u.ux, u.uy);
1265		    }
1266		    if (dmg) losehp(dmg, "scroll of earth", KILLED_BY_AN);
1267		}
1268	    }
1269	    break;
1270	case SCR_PUNISHMENT:
1271		known = TRUE;
1272		if(confused || sobj->blessed) {
1273			You_feel("guilty.");
1274			break;
1275		}
1276		punish(sobj);
1277		break;
1278	case SCR_STINKING_CLOUD: {
1279	        coord cc;
1280
1281		You("have found a scroll of stinking cloud!");
1282		known = TRUE;
1283		pline("Where do you want to center the cloud?");
1284		cc.x = u.ux;
1285		cc.y = u.uy;
1286		if (getpos(&cc, TRUE, "the desired position") < 0) {
1287		    pline(Never_mind);
1288		    return 0;
1289		}
1290		if (!cansee(cc.x, cc.y) || distu(cc.x, cc.y) >= 32) {
1291		    You("smell rotten eggs.");
1292		    return 0;
1293		}
1294		(void) create_gas_cloud(cc.x, cc.y, 3+bcsign(sobj),
1295						8+4*bcsign(sobj));
1296		break;
1297	}
1298	default:
1299		impossible("What weird effect is this? (%u)", sobj->otyp);
1300	}
1301	return(0);
1302}
1303
1304static void
1305wand_explode(obj)
1306register struct obj *obj;
1307{
1308    obj->in_use = TRUE;	/* in case losehp() is fatal */
1309    Your("%s vibrates violently, and explodes!",xname(obj));
1310    nhbell();
1311    losehp(rnd(2*(u.uhpmax+1)/3), "exploding wand", KILLED_BY_AN);
1312    useup(obj);
1313    exercise(A_STR, FALSE);
1314}
1315
1316/*
1317 * Low-level lit-field update routine.
1318 */
1319STATIC_PTR void
1320set_lit(x,y,val)
1321int x, y;
1322genericptr_t val;
1323{
1324	if (val)
1325	    levl[x][y].lit = 1;
1326	else {
1327	    levl[x][y].lit = 0;
1328	    snuff_light_source(x, y);
1329	}
1330}
1331
1332void
1333litroom(on,obj)
1334register boolean on;
1335struct obj *obj;
1336{
1337	char is_lit;	/* value is irrelevant; we use its address
1338			   as a `not null' flag for set_lit() */
1339
1340	/* first produce the text (provided you're not blind) */
1341	if(!on) {
1342		register struct obj *otmp;
1343
1344		if (!Blind) {
1345		    if(u.uswallow) {
1346			pline("It seems even darker in here than before.");
1347			return;
1348		    }
1349		    if (uwep && artifact_light(uwep) && uwep->lamplit)
1350			pline("Suddenly, the only light left comes from %s!",
1351				the(xname(uwep)));
1352		    else
1353			You("are surrounded by darkness!");
1354		}
1355
1356		/* the magic douses lamps, et al, too */
1357		for(otmp = invent; otmp; otmp = otmp->nobj)
1358		    if (otmp->lamplit)
1359			(void) snuff_lit(otmp);
1360		if (Blind) goto do_it;
1361	} else {
1362		if (Blind) goto do_it;
1363		if(u.uswallow){
1364			if (is_animal(u.ustuck->data))
1365				pline("%s %s is lit.",
1366				        s_suffix(Monnam(u.ustuck)),
1367					mbodypart(u.ustuck, STOMACH));
1368			else
1369				if (is_whirly(u.ustuck->data))
1370					pline("%s shines briefly.",
1371					      Monnam(u.ustuck));
1372				else
1373					pline("%s glistens.", Monnam(u.ustuck));
1374			return;
1375		}
1376		pline("A lit field surrounds you!");
1377	}
1378
1379do_it:
1380	/* No-op in water - can only see the adjacent squares and that's it! */
1381	if (Underwater || Is_waterlevel(&u.uz)) return;
1382	/*
1383	 *  If we are darkening the room and the hero is punished but not
1384	 *  blind, then we have to pick up and replace the ball and chain so
1385	 *  that we don't remember them if they are out of sight.
1386	 */
1387	if (Punished && !on && !Blind)
1388	    move_bc(1, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
1389
1390#ifdef REINCARNATION
1391	if (Is_rogue_level(&u.uz)) {
1392	    /* Can't use do_clear_area because MAX_RADIUS is too small */
1393	    /* rogue lighting must light the entire room */
1394	    int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET;
1395	    int rx, ry;
1396	    if(rnum >= 0) {
1397		for(rx = rooms[rnum].lx-1; rx <= rooms[rnum].hx+1; rx++)
1398		    for(ry = rooms[rnum].ly-1; ry <= rooms[rnum].hy+1; ry++)
1399			set_lit(rx, ry,
1400				(genericptr_t)(on ? &is_lit : (char *)0));
1401		rooms[rnum].rlit = on;
1402	    }
1403	    /* hallways remain dark on the rogue level */
1404	} else
1405#endif
1406	    do_clear_area(u.ux,u.uy,
1407		(obj && obj->oclass==SCROLL_CLASS && obj->blessed) ? 9 : 5,
1408		set_lit, (genericptr_t)(on ? &is_lit : (char *)0));
1409
1410	/*
1411	 *  If we are not blind, then force a redraw on all positions in sight
1412	 *  by temporarily blinding the hero.  The vision recalculation will
1413	 *  correctly update all previously seen positions *and* correctly
1414	 *  set the waslit bit [could be messed up from above].
1415	 */
1416	if (!Blind) {
1417	    vision_recalc(2);
1418
1419	    /* replace ball&chain */
1420	    if (Punished && !on)
1421		move_bc(0, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
1422	}
1423
1424	vision_full_recalc = 1;	/* delayed vision recalculation */
1425}
1426
1427static void
1428do_class_genocide()
1429{
1430	int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0;
1431	char buf[BUFSZ];
1432	boolean gameover = FALSE;	/* true iff killed self */
1433
1434	for(j=0; ; j++) {
1435		if (j >= 5) {
1436			pline(thats_enough_tries);
1437			return;
1438		}
1439		do {
1440		    getlin("What class of monsters do you wish to genocide?",
1441			buf);
1442		    (void)mungspaces(buf);
1443		} while (buf[0]=='\033' || !buf[0]);
1444		/* choosing "none" preserves genocideless conduct */
1445		if (!strcmpi(buf, "none") ||
1446		    !strcmpi(buf, "nothing")) return;
1447
1448		if (strlen(buf) == 1) {
1449		    if (buf[0] == ILLOBJ_SYM)
1450			buf[0] = def_monsyms[S_MIMIC];
1451		    class = def_char_to_monclass(buf[0]);
1452		} else {
1453		    char buf2[BUFSZ];
1454
1455		    class = 0;
1456		    Strcpy(buf2, makesingular(buf));
1457		    Strcpy(buf, buf2);
1458		}
1459		immunecnt = gonecnt = goodcnt = 0;
1460		for (i = LOW_PM; i < NUMMONS; i++) {
1461		    if (class == 0 &&
1462			    strstri(monexplain[(int)mons[i].mlet], buf) != 0)
1463			class = mons[i].mlet;
1464		    if (mons[i].mlet == class) {
1465			if (!(mons[i].geno & G_GENO)) immunecnt++;
1466			else if(mvitals[i].mvflags & G_GENOD) gonecnt++;
1467			else goodcnt++;
1468		    }
1469		}
1470		/*
1471		 * TODO[?]: If user's input doesn't match any class
1472		 *	    description, check individual species names.
1473		 */
1474		if (!goodcnt && class != mons[urole.malenum].mlet &&
1475				class != mons[urace.malenum].mlet) {
1476			if (gonecnt)
1477	pline("All such monsters are already nonexistent.");
1478			else if (immunecnt ||
1479				(buf[0] == DEF_INVISIBLE && buf[1] == '\0'))
1480	You("aren't permitted to genocide such monsters.");
1481			else
1482#ifdef WIZARD	/* to aid in topology testing; remove pesky monsters */
1483			  if (wizard && buf[0] == '*') {
1484			    register struct monst *mtmp, *mtmp2;
1485
1486			    gonecnt = 0;
1487			    for (mtmp = fmon; mtmp; mtmp = mtmp2) {
1488				mtmp2 = mtmp->nmon;
1489			    	if (DEADMONSTER(mtmp)) continue;
1490				mongone(mtmp);
1491				gonecnt++;
1492			    }
1493	pline("Eliminated %d monster%s.", gonecnt, plur(gonecnt));
1494			    return;
1495			} else
1496#endif
1497	pline("That symbol does not represent any monster.");
1498			continue;
1499		}
1500
1501		for (i = LOW_PM; i < NUMMONS; i++) {
1502		    if(mons[i].mlet == class) {
1503			char nam[BUFSZ];
1504
1505			Strcpy(nam, makeplural(mons[i].mname));
1506			/* Although "genus" is Latin for race, the hero benefits
1507			 * from both race and role; thus genocide affects either.
1508			 */
1509			if (Your_Own_Role(i) || Your_Own_Race(i) ||
1510				((mons[i].geno & G_GENO)
1511				&& !(mvitals[i].mvflags & G_GENOD))) {
1512			/* This check must be first since player monsters might
1513			 * have G_GENOD or !G_GENO.
1514			 */
1515			    mvitals[i].mvflags |= (G_GENOD|G_NOCORPSE);
1516			    reset_rndmonst(i);
1517			    kill_genocided_monsters();
1518			    update_inventory();		/* eggs & tins */
1519			    pline("Wiped out all %s.", nam);
1520			    if (Upolyd && i == u.umonnum) {
1521				u.mh = -1;
1522				if (Unchanging) {
1523				    if (!feel_dead++) You("die.");
1524				    /* finish genociding this class of
1525				       monsters before ultimately dying */
1526				    gameover = TRUE;
1527				} else
1528				    rehumanize();
1529			    }
1530			    /* Self-genocide if it matches either your race
1531			       or role.  Assumption:  male and female forms
1532			       share same monster class. */
1533			    if (i == urole.malenum || i == urace.malenum) {
1534				u.uhp = -1;
1535				if (Upolyd) {
1536				    if (!feel_dead++) You_feel("dead inside.");
1537				} else {
1538				    if (!feel_dead++) You("die.");
1539				    gameover = TRUE;
1540				}
1541			    }
1542			} else if (mvitals[i].mvflags & G_GENOD) {
1543			    if (!gameover)
1544				pline("All %s are already nonexistent.", nam);
1545			} else if (!gameover) {
1546			  /* suppress feedback about quest beings except
1547			     for those applicable to our own role */
1548			  if ((mons[i].msound != MS_LEADER ||
1549			       quest_info(MS_LEADER) == i)
1550			   && (mons[i].msound != MS_NEMESIS ||
1551			       quest_info(MS_NEMESIS) == i)
1552			   && (mons[i].msound != MS_GUARDIAN ||
1553			       quest_info(MS_GUARDIAN) == i)
1554			/* non-leader/nemesis/guardian role-specific monster */
1555			   && (i != PM_NINJA ||		/* nuisance */
1556			       Role_if(PM_SAMURAI))) {
1557				boolean named, uniq;
1558
1559				named = type_is_pname(&mons[i]) ? TRUE : FALSE;
1560				uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE;
1561				/* one special case */
1562				if (i == PM_HIGH_PRIEST) uniq = FALSE;
1563
1564				You("aren't permitted to genocide %s%s.",
1565				    (uniq && !named) ? "the " : "",
1566				    (uniq || named) ? mons[i].mname : nam);
1567			    }
1568			}
1569		    }
1570		}
1571		if (gameover || u.uhp == -1) {
1572		    killer_format = KILLED_BY_AN;
1573		    killer = "scroll of genocide";
1574		    if (gameover) done(GENOCIDED);
1575		}
1576		return;
1577	}
1578}
1579
1580#define REALLY 1
1581#define PLAYER 2
1582#define ONTHRONE 4
1583void
1584do_genocide(how)
1585int how;
1586/* 0 = no genocide; create monsters (cursed scroll) */
1587/* 1 = normal genocide */
1588/* 3 = forced genocide of player */
1589/* 5 (4 | 1) = normal genocide from throne */
1590{
1591	char buf[BUFSZ];
1592	register int	i, killplayer = 0;
1593	register int mndx;
1594	register struct permonst *ptr;
1595	const char *which;
1596
1597	if (how & PLAYER) {
1598		mndx = u.umonster;	/* non-polymorphed mon num */
1599		ptr = &mons[mndx];
1600		Strcpy(buf, ptr->mname);
1601		killplayer++;
1602	} else {
1603	    for(i = 0; ; i++) {
1604		if(i >= 5) {
1605		    pline(thats_enough_tries);
1606		    return;
1607		}
1608		getlin("What monster do you want to genocide? [type the name]",
1609			buf);
1610		(void)mungspaces(buf);
1611		/* choosing "none" preserves genocideless conduct */
1612		if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) {
1613		    /* ... but no free pass if cursed */
1614		    if (!(how & REALLY)) {
1615			ptr = rndmonst();
1616			if (!ptr) return; /* no message, like normal case */
1617			mndx = monsndx(ptr);
1618			break;		/* remaining checks don't apply */
1619		    } else return;
1620		}
1621
1622		mndx = name_to_mon(buf);
1623		if (mndx == NON_PM || (mvitals[mndx].mvflags & G_GENOD)) {
1624			pline("Such creatures %s exist in this world.",
1625			      (mndx == NON_PM) ? "do not" : "no longer");
1626			continue;
1627		}
1628		ptr = &mons[mndx];
1629		/* Although "genus" is Latin for race, the hero benefits
1630		 * from both race and role; thus genocide affects either.
1631		 */
1632		if (Your_Own_Role(mndx) || Your_Own_Race(mndx)) {
1633			killplayer++;
1634			break;
1635		}
1636		if (is_human(ptr)) adjalign(-sgn(u.ualign.type));
1637		if (is_demon(ptr)) adjalign(sgn(u.ualign.type));
1638
1639		if(!(ptr->geno & G_GENO)) {
1640			if(flags.soundok) {
1641	/* fixme: unconditional "caverns" will be silly in some circumstances */
1642			    if(flags.verbose)
1643			pline("A thunderous voice booms through the caverns:");
1644			    verbalize("No, mortal!  That will not be done.");
1645			}
1646			continue;
1647		}
1648		/* KMH -- Unchanging prevents rehumanization */
1649		if (Unchanging && ptr == youmonst.data)
1650		    killplayer++;
1651		break;
1652	    }
1653	}
1654
1655	which = "all ";
1656	if (Hallucination) {
1657	    if (Upolyd)
1658		Strcpy(buf,youmonst.data->mname);
1659	    else {
1660		Strcpy(buf, (flags.female && urole.name.f) ?
1661				urole.name.f : urole.name.m);
1662		buf[0] = lowc(buf[0]);
1663	    }
1664	} else {
1665	    Strcpy(buf, ptr->mname); /* make sure we have standard singular */
1666	    if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST])
1667		which = !type_is_pname(ptr) ? "the " : "";
1668	}
1669	if (how & REALLY) {
1670	    /* setting no-corpse affects wishing and random tin generation */
1671	    mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE);
1672	    pline("Wiped out %s%s.", which,
1673		  (*which != 'a') ? buf : makeplural(buf));
1674
1675	    if (killplayer) {
1676		/* might need to wipe out dual role */
1677		if (urole.femalenum != NON_PM && mndx == urole.malenum)
1678		    mvitals[urole.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
1679		if (urole.femalenum != NON_PM && mndx == urole.femalenum)
1680		    mvitals[urole.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
1681		if (urace.femalenum != NON_PM && mndx == urace.malenum)
1682		    mvitals[urace.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
1683		if (urace.femalenum != NON_PM && mndx == urace.femalenum)
1684		    mvitals[urace.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
1685
1686		u.uhp = -1;
1687		if (how & PLAYER) {
1688		    killer_format = KILLED_BY;
1689		    killer = "genocidal confusion";
1690		} else if (how & ONTHRONE) {
1691		    /* player selected while on a throne */
1692		    killer_format = KILLED_BY_AN;
1693		    killer = "imperious order";
1694		} else { /* selected player deliberately, not confused */
1695		    killer_format = KILLED_BY_AN;
1696		    killer = "scroll of genocide";
1697		}
1698
1699	/* Polymorphed characters will die as soon as they're rehumanized. */
1700	/* KMH -- Unchanging prevents rehumanization */
1701		if (Upolyd && ptr != youmonst.data) {
1702			delayed_killer = killer;
1703			killer = 0;
1704			You_feel("dead inside.");
1705		} else
1706			done(GENOCIDED);
1707	    } else if (ptr == youmonst.data) {
1708		rehumanize();
1709	    }
1710	    reset_rndmonst(mndx);
1711	    kill_genocided_monsters();
1712	    update_inventory();	/* in case identified eggs were affected */
1713	} else {
1714	    int cnt = 0;
1715
1716	    if (!(mons[mndx].geno & G_UNIQ) &&
1717		    !(mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT)))
1718		for (i = rn1(3, 4); i > 0; i--) {
1719		    if (!makemon(ptr, u.ux, u.uy, NO_MINVENT))
1720			break;	/* couldn't make one */
1721		    ++cnt;
1722		    if (mvitals[mndx].mvflags & G_EXTINCT)
1723			break;	/* just made last one */
1724		}
1725	    if (cnt)
1726		pline("Sent in some %s.", makeplural(buf));
1727	    else
1728		pline(nothing_happens);
1729	}
1730}
1731
1732void
1733punish(sobj)
1734register struct obj	*sobj;
1735{
1736	/* KMH -- Punishment is still okay when you are riding */
1737	You("are being punished for your misbehavior!");
1738	if(Punished){
1739		Your("iron ball gets heavier.");
1740		uball->owt += 160 * (1 + sobj->cursed);
1741		return;
1742	}
1743	if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
1744		pline("A ball and chain appears, then falls away.");
1745		dropy(mkobj(BALL_CLASS, TRUE));
1746		return;
1747	}
1748	setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN);
1749	setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
1750	uball->spe = 1;		/* special ball (see save) */
1751
1752	/*
1753	 *  Place ball & chain if not swallowed.  If swallowed, the ball &
1754	 *  chain variables will be set at the next call to placebc().
1755	 */
1756	if (!u.uswallow) {
1757	    placebc();
1758	    if (Blind) set_bc(1);	/* set up ball and chain variables */
1759	    newsym(u.ux,u.uy);		/* see ball&chain if can't see self */
1760	}
1761}
1762
1763void
1764unpunish()
1765{	    /* remove the ball and chain */
1766	struct obj *savechain = uchain;
1767
1768	obj_extract_self(uchain);
1769	newsym(uchain->ox,uchain->oy);
1770	setworn((struct obj *)0, W_CHAIN);
1771	dealloc_obj(savechain);
1772	uball->spe = 0;
1773	setworn((struct obj *)0, W_BALL);
1774}
1775
1776/* some creatures have special data structures that only make sense in their
1777 * normal locations -- if the player tries to create one elsewhere, or to revive
1778 * one, the disoriented creature becomes a zombie
1779 */
1780boolean
1781cant_create(mtype, revival)
1782int *mtype;
1783boolean revival;
1784{
1785
1786	/* SHOPKEEPERS can be revived now */
1787	if (*mtype==PM_GUARD || (*mtype==PM_SHOPKEEPER && !revival)
1788	     || *mtype==PM_ALIGNED_PRIEST || *mtype==PM_ANGEL) {
1789		*mtype = PM_HUMAN_ZOMBIE;
1790		return TRUE;
1791	} else if (*mtype==PM_LONG_WORM_TAIL) {	/* for create_particular() */
1792		*mtype = PM_LONG_WORM;
1793		return TRUE;
1794	}
1795	return FALSE;
1796}
1797
1798#ifdef WIZARD
1799/*
1800 * Make a new monster with the type controlled by the user.
1801 *
1802 * Note:  when creating a monster by class letter, specifying the
1803 * "strange object" (']') symbol produces a random monster rather
1804 * than a mimic; this behavior quirk is useful so don't "fix" it...
1805 */
1806boolean
1807create_particular()
1808{
1809	char buf[BUFSZ], *bufp, monclass = MAXMCLASSES;
1810	int which, tries, i;
1811	struct permonst *whichpm;
1812	struct monst *mtmp;
1813	boolean madeany = FALSE;
1814	boolean maketame, makepeaceful, makehostile;
1815
1816	tries = 0;
1817	do {
1818	    which = urole.malenum;	/* an arbitrary index into mons[] */
1819	    maketame = makepeaceful = makehostile = FALSE;
1820	    getlin("Create what kind of monster? [type the name or symbol]",
1821		   buf);
1822	    bufp = mungspaces(buf);
1823	    if (*bufp == '\033') return FALSE;
1824	    /* allow the initial disposition to be specified */
1825	    if (!strncmpi(bufp, "tame ", 5)) {
1826		bufp += 5;
1827		maketame = TRUE;
1828	    } else if (!strncmpi(bufp, "peaceful ", 9)) {
1829		bufp += 9;
1830		makepeaceful = TRUE;
1831	    } else if (!strncmpi(bufp, "hostile ", 8)) {
1832		bufp += 8;
1833		makehostile = TRUE;
1834	    }
1835	    /* decide whether a valid monster was chosen */
1836	    if (strlen(bufp) == 1) {
1837		monclass = def_char_to_monclass(*bufp);
1838		if (monclass != MAXMCLASSES) break;	/* got one */
1839	    } else {
1840		which = name_to_mon(bufp);
1841		if (which >= LOW_PM) break;		/* got one */
1842	    }
1843	    /* no good; try again... */
1844	    pline("I've never heard of such monsters.");
1845	} while (++tries < 5);
1846
1847	if (tries == 5) {
1848	    pline(thats_enough_tries);
1849	} else {
1850	    (void) cant_create(&which, FALSE);
1851	    whichpm = &mons[which];
1852	    for (i = 0; i <= multi; i++) {
1853		if (monclass != MAXMCLASSES)
1854		    whichpm = mkclass(monclass, 0);
1855		if (maketame) {
1856		    mtmp = makemon(whichpm, u.ux, u.uy, MM_EDOG);
1857		    if (mtmp) {
1858			initedog(mtmp);
1859			set_malign(mtmp);
1860		    }
1861		} else {
1862		    mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
1863		    if ((makepeaceful || makehostile) && mtmp) {
1864			mtmp->mtame = 0;	/* sanity precaution */
1865			mtmp->mpeaceful = makepeaceful ? 1 : 0;
1866			set_malign(mtmp);
1867		    }
1868		}
1869		if (mtmp) madeany = TRUE;
1870	    }
1871	}
1872	return madeany;
1873}
1874#endif /* WIZARD */
1875
1876#endif /* OVLB */
1877
1878/*read.c*/
1879