1/*	SCCS Id: @(#)polyself.c	3.4	2003/01/08	*/
2/*	Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
3/* NetHack may be freely redistributed.  See license for details. */
4
5/*
6 * Polymorph self routine.
7 *
8 * Note:  the light source handling code assumes that both youmonst.m_id
9 * and youmonst.mx will always remain 0 when it handles the case of the
10 * player polymorphed into a light-emitting monster.
11 */
12
13#include "hack.h"
14
15#ifdef OVLB
16STATIC_DCL void FDECL(polyman, (const char *,const char *));
17STATIC_DCL void NDECL(break_armor);
18STATIC_DCL void FDECL(drop_weapon,(int));
19STATIC_DCL void NDECL(uunstick);
20STATIC_DCL int FDECL(armor_to_dragon,(int));
21STATIC_DCL void NDECL(newman);
22
23/* update the youmonst.data structure pointer */
24void
25set_uasmon()
26{
27	set_mon_data(&youmonst, &mons[u.umonnum], 0);
28}
29
30/* make a (new) human out of the player */
31STATIC_OVL void
32polyman(fmt, arg)
33const char *fmt, *arg;
34{
35	boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
36		was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT);
37	boolean could_pass_walls = Passes_walls;
38	boolean was_blind = !!Blind;
39
40	if (Upolyd) {
41		u.acurr = u.macurr;	/* restore old attribs */
42		u.amax = u.mamax;
43		u.umonnum = u.umonster;
44		flags.female = u.mfemale;
45	}
46	set_uasmon();
47
48	u.mh = u.mhmax = 0;
49	u.mtimedone = 0;
50	skinback(FALSE);
51	u.uundetected = 0;
52
53	if (sticky) uunstick();
54	find_ac();
55	if (was_mimicking) {
56	    if (multi < 0) unmul("");
57	    youmonst.m_ap_type = M_AP_NOTHING;
58	}
59
60	newsym(u.ux,u.uy);
61
62	You(fmt, arg);
63	/* check whether player foolishly genocided self while poly'd */
64	if ((mvitals[urole.malenum].mvflags & G_GENOD) ||
65			(urole.femalenum != NON_PM &&
66			(mvitals[urole.femalenum].mvflags & G_GENOD)) ||
67			(mvitals[urace.malenum].mvflags & G_GENOD) ||
68			(urace.femalenum != NON_PM &&
69			(mvitals[urace.femalenum].mvflags & G_GENOD))) {
70	    /* intervening activity might have clobbered genocide info */
71	    killer = delayed_killer;
72	    if (!killer || !strstri(killer, "genocid")) {
73		killer_format = KILLED_BY;
74		killer = "self-genocide";
75	    }
76	    done(GENOCIDED);
77	}
78
79	if (u.twoweap && !could_twoweap(youmonst.data))
80	    untwoweapon();
81
82	if (u.utraptype == TT_PIT) {
83	    if (could_pass_walls) {	/* player forms cannot pass walls */
84		u.utrap = rn1(6,2);
85	    }
86	}
87	if (was_blind && !Blind) {	/* reverting from eyeless */
88	    Blinded = 1L;
89	    make_blinded(0L, TRUE);	/* remove blindness */
90	}
91
92	if(!Levitation && !u.ustuck &&
93	   (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy)))
94		spoteffects(TRUE);
95
96	see_monsters();
97}
98
99void
100change_sex()
101{
102	/* setting u.umonster for caveman/cavewoman or priest/priestess
103	   swap unintentionally makes `Upolyd' appear to be true */
104	boolean already_polyd = (boolean) Upolyd;
105
106	/* Some monsters are always of one sex and their sex can't be changed */
107	/* succubi/incubi can change, but are handled below */
108	/* !already_polyd check necessary because is_male() and is_female()
109           are true if the player is a priest/priestess */
110	if (!already_polyd || (!is_male(youmonst.data) && !is_female(youmonst.data) && !is_neuter(youmonst.data)))
111	    flags.female = !flags.female;
112	if (already_polyd)	/* poly'd: also change saved sex */
113	    u.mfemale = !u.mfemale;
114	max_rank_sz();		/* [this appears to be superfluous] */
115	if ((already_polyd ? u.mfemale : flags.female) && urole.name.f)
116	    Strcpy(pl_character, urole.name.f);
117	else
118	    Strcpy(pl_character, urole.name.m);
119	u.umonster = ((already_polyd ? u.mfemale : flags.female) && urole.femalenum != NON_PM) ?
120			urole.femalenum : urole.malenum;
121	if (!already_polyd) {
122	    u.umonnum = u.umonster;
123	} else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) {
124	    flags.female = !flags.female;
125	    /* change monster type to match new sex */
126	    u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS;
127	    set_uasmon();
128	}
129}
130
131STATIC_OVL void
132newman()
133{
134	int tmp, oldlvl;
135
136	tmp = u.uhpmax;
137	oldlvl = u.ulevel;
138	u.ulevel = u.ulevel + rn1(5, -2);
139	if (u.ulevel > 127 || u.ulevel < 1) { /* level went below 0? */
140	    u.ulevel = oldlvl; /* restore old level in case they lifesave */
141	    goto dead;
142	}
143	if (u.ulevel > MAXULEV) u.ulevel = MAXULEV;
144	/* If your level goes down, your peak level goes down by
145	   the same amount so that you can't simply use blessed
146	   full healing to undo the decrease.  But if your level
147	   goes up, your peak level does *not* undergo the same
148	   adjustment; you might end up losing out on the chance
149	   to regain some levels previously lost to other causes. */
150	if (u.ulevel < oldlvl) u.ulevelmax -= (oldlvl - u.ulevel);
151	if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
152
153	if (!rn2(10)) change_sex();
154
155	adjabil(oldlvl, (int)u.ulevel);
156	reset_rndmonst(NON_PM);	/* new monster generation criteria */
157
158	/* random experience points for the new experience level */
159	u.uexp = rndexp(FALSE);
160
161	/* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level
162	 * -10 and +10: don't apply proportionate HP to 10 of a starting
163	 *   character's hit points (since a starting character's hit points
164	 *   are not on the same scale with hit points obtained through level
165	 *   gain)
166	 * 9 - rn2(19): random change of -9 to +9 hit points
167	 */
168#ifndef LINT
169	u.uhpmax = ((u.uhpmax - 10) * (long)u.ulevel / oldlvl + 10) +
170		(9 - rn2(19));
171#endif
172
173#ifdef LINT
174	u.uhp = u.uhp + tmp;
175#else
176	u.uhp = u.uhp * (long)u.uhpmax/tmp;
177#endif
178
179	tmp = u.uenmax;
180#ifndef LINT
181	u.uenmax = u.uenmax * (long)u.ulevel / oldlvl + 9 - rn2(19);
182#endif
183	if (u.uenmax < 0) u.uenmax = 0;
184#ifndef LINT
185	u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax);
186#endif
187
188	redist_attr();
189	u.uhunger = rn1(500,500);
190	if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
191	Stoned = 0;
192	delayed_killer = 0;
193	if (u.uhp <= 0 || u.uhpmax <= 0) {
194		if (Polymorph_control) {
195		    if (u.uhp <= 0) u.uhp = 1;
196		    if (u.uhpmax <= 0) u.uhpmax = 1;
197		} else {
198dead: /* we come directly here if their experience level went to 0 or less */
199		    Your("new form doesn't seem healthy enough to survive.");
200		    killer_format = KILLED_BY_AN;
201		    killer="unsuccessful polymorph";
202		    done(DIED);
203		    newuhs(FALSE);
204		    return; /* lifesaved */
205		}
206	}
207	newuhs(FALSE);
208	polyman("feel like a new %s!",
209		(flags.female && urace.individual.f) ? urace.individual.f :
210		(urace.individual.m) ? urace.individual.m : urace.noun);
211	if (Slimed) {
212		Your("body transforms, but there is still slime on you.");
213		Slimed = 10L;
214	}
215	flags.botl = 1;
216	see_monsters();
217	(void) encumber_msg();
218}
219
220void
221polyself(forcecontrol)
222boolean forcecontrol;
223{
224	char buf[BUFSZ];
225	int old_light, new_light;
226	int mntmp = NON_PM;
227	int tries=0;
228	boolean draconian = (uarm &&
229				uarm->otyp >= GRAY_DRAGON_SCALE_MAIL &&
230				uarm->otyp <= YELLOW_DRAGON_SCALES);
231	boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data));
232	boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT);
233	boolean was_floating = (Levitation || Flying);
234
235        if(!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) {
236	    if (rn2(20) > ACURR(A_CON)) {
237		You(shudder_for_moment);
238		losehp(rnd(30), "system shock", KILLED_BY_AN);
239		exercise(A_CON, FALSE);
240		return;
241	    }
242	}
243	old_light = Upolyd ? emits_light(youmonst.data) : 0;
244
245	if (Polymorph_control || forcecontrol) {
246		do {
247			getlin("Become what kind of monster? [type the name]",
248				buf);
249			mntmp = name_to_mon(buf);
250			if (mntmp < LOW_PM)
251				pline("I've never heard of such monsters.");
252			/* Note:  humans are illegal as monsters, but an
253			 * illegal monster forces newman(), which is what we
254			 * want if they specified a human.... */
255			else if (!polyok(&mons[mntmp]) && !your_race(&mons[mntmp]))
256				You("cannot polymorph into that.");
257			else break;
258		} while(++tries < 5);
259		if (tries==5) pline(thats_enough_tries);
260		/* allow skin merging, even when polymorph is controlled */
261		if (draconian &&
262		    (mntmp == armor_to_dragon(uarm->otyp) || tries == 5))
263		    goto do_merge;
264	} else if (draconian || iswere || isvamp) {
265		/* special changes that don't require polyok() */
266		if (draconian) {
267		    do_merge:
268			mntmp = armor_to_dragon(uarm->otyp);
269			if (!(mvitals[mntmp].mvflags & G_GENOD)) {
270				/* allow G_EXTINCT */
271				You("merge with your scaly armor.");
272				uskin = uarm;
273				uarm = (struct obj *)0;
274				/* save/restore hack */
275				uskin->owornmask |= I_SPECIAL;
276			}
277		} else if (iswere) {
278			if (is_were(youmonst.data))
279				mntmp = PM_HUMAN; /* Illegal; force newman() */
280			else
281				mntmp = u.ulycn;
282		} else {
283			if (youmonst.data->mlet == S_VAMPIRE)
284				mntmp = PM_VAMPIRE_BAT;
285			else
286				mntmp = PM_VAMPIRE;
287		}
288		/* if polymon fails, "you feel" message has been given
289		   so don't follow up with another polymon or newman */
290		if (mntmp == PM_HUMAN) newman();	/* werecritter */
291		else (void) polymon(mntmp);
292		goto made_change;    /* maybe not, but this is right anyway */
293	}
294
295	if (mntmp < LOW_PM) {
296		tries = 0;
297		do {
298			/* randomly pick an "ordinary" monster */
299			mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
300		} while((!polyok(&mons[mntmp]) || is_placeholder(&mons[mntmp]))
301				&& tries++ < 200);
302	}
303
304	/* The below polyok() fails either if everything is genocided, or if
305	 * we deliberately chose something illegal to force newman().
306	 */
307	if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp]))
308		newman();
309	else if(!polymon(mntmp)) return;
310
311	if (!uarmg) selftouch("No longer petrify-resistant, you");
312
313 made_change:
314	new_light = Upolyd ? emits_light(youmonst.data) : 0;
315	if (old_light != new_light) {
316	    if (old_light)
317		del_light_source(LS_MONSTER, (genericptr_t)&youmonst);
318	    if (new_light == 1) ++new_light;  /* otherwise it's undetectable */
319	    if (new_light)
320		new_light_source(u.ux, u.uy, new_light,
321				 LS_MONSTER, (genericptr_t)&youmonst);
322	}
323	if (is_pool(u.ux,u.uy) && was_floating && !(Levitation || Flying) &&
324		!breathless(youmonst.data) && !amphibious(youmonst.data) &&
325		!Swimming) drown();
326}
327
328/* (try to) make a mntmp monster out of the player */
329int
330polymon(mntmp)	/* returns 1 if polymorph successful */
331int	mntmp;
332{
333	boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
334		was_blind = !!Blind, dochange = FALSE;
335	boolean could_pass_walls = Passes_walls;
336	int mlvl;
337
338	if (mvitals[mntmp].mvflags & G_GENOD) {	/* allow G_EXTINCT */
339		You_feel("rather %s-ish.",mons[mntmp].mname);
340		exercise(A_WIS, TRUE);
341		return(0);
342	}
343
344	/* KMH, conduct */
345	u.uconduct.polyselfs++;
346
347	if (!Upolyd) {
348		/* Human to monster; save human stats */
349		u.macurr = u.acurr;
350		u.mamax = u.amax;
351		u.mfemale = flags.female;
352	} else {
353		/* Monster to monster; restore human stats, to be
354		 * immediately changed to provide stats for the new monster
355		 */
356		u.acurr = u.macurr;
357		u.amax = u.mamax;
358		flags.female = u.mfemale;
359	}
360
361	if (youmonst.m_ap_type) {
362	    /* stop mimicking immediately */
363	    if (multi < 0) unmul("");
364	} else if (mons[mntmp].mlet != S_MIMIC) {
365	    /* as in polyman() */
366	    youmonst.m_ap_type = M_AP_NOTHING;
367	}
368	if (is_male(&mons[mntmp])) {
369		if(flags.female) dochange = TRUE;
370	} else if (is_female(&mons[mntmp])) {
371		if(!flags.female) dochange = TRUE;
372	} else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) {
373		if(!rn2(10)) dochange = TRUE;
374	}
375	if (dochange) {
376		flags.female = !flags.female;
377		You("%s %s%s!",
378		    (u.umonnum != mntmp) ? "turn into a" : "feel like a new",
379		    (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" :
380			flags.female ? "female " : "male ",
381		    mons[mntmp].mname);
382	} else {
383		if (u.umonnum != mntmp)
384			You("turn into %s!", an(mons[mntmp].mname));
385		else
386			You_feel("like a new %s!", mons[mntmp].mname);
387	}
388	if (Stoned && poly_when_stoned(&mons[mntmp])) {
389		/* poly_when_stoned already checked stone golem genocide */
390		You("turn to stone!");
391		mntmp = PM_STONE_GOLEM;
392		Stoned = 0;
393		delayed_killer = 0;
394	}
395
396	u.mtimedone = rn1(500, 500);
397	u.umonnum = mntmp;
398	set_uasmon();
399
400	/* New stats for monster, to last only as long as polymorphed.
401	 * Currently only strength gets changed.
402	 */
403	if(strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100);
404
405	if (Stone_resistance && Stoned) { /* parnes@eniac.seas.upenn.edu */
406		Stoned = 0;
407		delayed_killer = 0;
408		You("no longer seem to be petrifying.");
409	}
410	if (Sick_resistance && Sick) {
411		make_sick(0L, (char *) 0, FALSE, SICK_ALL);
412		You("no longer feel sick.");
413	}
414	if (Slimed) {
415	    if (flaming(youmonst.data)) {
416		pline_The("slime burns away!");
417		Slimed = 0L;
418		flags.botl = 1;
419	    } else if (mntmp == PM_GREEN_SLIME) {
420		/* do it silently */
421		Slimed = 0L;
422		flags.botl = 1;
423	    }
424	}
425	if (nohands(youmonst.data)) Glib = 0;
426
427	/*
428	mlvl = adj_lev(&mons[mntmp]);
429	 * We can't do the above, since there's no such thing as an
430	 * "experience level of you as a monster" for a polymorphed character.
431	 */
432	mlvl = (int)mons[mntmp].mlevel;
433	if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) {
434		u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + d(mlvl,4));
435	} else if (is_golem(youmonst.data)) {
436		u.mhmax = golemhp(mntmp);
437	} else {
438		if (!mlvl) u.mhmax = rnd(4);
439		else u.mhmax = d(mlvl, 8);
440		if (is_home_elemental(&mons[mntmp])) u.mhmax *= 3;
441	}
442	u.mh = u.mhmax;
443
444	if (u.ulevel < mlvl) {
445	/* Low level characters can't become high level monsters for long */
446#ifdef DUMB
447		/* DRS/NS 2.2.6 messes up -- Peter Kendell */
448		int mtd = u.mtimedone, ulv = u.ulevel;
449
450		u.mtimedone = mtd * ulv / mlvl;
451#else
452		u.mtimedone = u.mtimedone * u.ulevel / mlvl;
453#endif
454	}
455
456	if (uskin && mntmp != armor_to_dragon(uskin->otyp))
457		skinback(FALSE);
458	break_armor();
459	drop_weapon(1);
460	if (hides_under(youmonst.data))
461		u.uundetected = OBJ_AT(u.ux, u.uy);
462	else if (youmonst.data->mlet == S_EEL)
463		u.uundetected = is_pool(u.ux, u.uy);
464	else
465		u.uundetected = 0;
466
467	if (u.utraptype == TT_PIT) {
468	    if (could_pass_walls && !Passes_walls) {
469		u.utrap = rn1(6,2);
470	    } else if (!could_pass_walls && Passes_walls) {
471		u.utrap = 0;
472	    }
473	}
474	if (was_blind && !Blind) {	/* previous form was eyeless */
475	    Blinded = 1L;
476	    make_blinded(0L, TRUE);	/* remove blindness */
477	}
478	newsym(u.ux,u.uy);		/* Change symbol */
479
480	if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0;
481	else if (sticky && !sticks(youmonst.data)) uunstick();
482#ifdef STEED
483	if (u.usteed) {
484	    if (touch_petrifies(u.usteed->data) &&
485	    		!Stone_resistance && rnl(3)) {
486	    	char buf[BUFSZ];
487
488	    	pline("No longer petrifying-resistant, you touch %s.",
489	    			mon_nam(u.usteed));
490	    	Sprintf(buf, "riding %s", an(u.usteed->data->mname));
491	    	instapetrify(buf);
492 	    }
493	    if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY);
494	}
495#endif
496
497	if (flags.verbose) {
498	    static const char use_thec[] = "Use the command #%s to %s.";
499	    static const char monsterc[] = "monster";
500	    if (can_breathe(youmonst.data))
501		pline(use_thec,monsterc,"use your breath weapon");
502	    if (attacktype(youmonst.data, AT_SPIT))
503		pline(use_thec,monsterc,"spit venom");
504	    if (youmonst.data->mlet == S_NYMPH)
505		pline(use_thec,monsterc,"remove an iron ball");
506	    if (attacktype(youmonst.data, AT_GAZE))
507		pline(use_thec,monsterc,"gaze at monsters");
508	    if (is_hider(youmonst.data))
509		pline(use_thec,monsterc,"hide");
510	    if (is_were(youmonst.data))
511		pline(use_thec,monsterc,"summon help");
512	    if (webmaker(youmonst.data))
513		pline(use_thec,monsterc,"spin a web");
514	    if (u.umonnum == PM_GREMLIN)
515		pline(use_thec,monsterc,"multiply in a fountain");
516	    if (is_unicorn(youmonst.data))
517		pline(use_thec,monsterc,"use your horn");
518	    if (is_mind_flayer(youmonst.data))
519		pline(use_thec,monsterc,"emit a mental blast");
520	    if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */
521		pline(use_thec,monsterc,"shriek");
522	    if (lays_eggs(youmonst.data) && flags.female)
523		pline(use_thec,"sit","lay an egg");
524	}
525	/* you now know what an egg of your type looks like */
526	if (lays_eggs(youmonst.data)) {
527	    learn_egg_type(u.umonnum);
528	    /* make queen bees recognize killer bee eggs */
529	    learn_egg_type(egg_type_from_parent(u.umonnum, TRUE));
530	}
531	find_ac();
532	if((!Levitation && !u.ustuck && !Flying &&
533	    (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) ||
534	   (Underwater && !Swimming))
535	    spoteffects(TRUE);
536	if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) {
537	    u.utrap = 0;
538	    pline_The("rock seems to no longer trap you.");
539	} else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) {
540	    u.utrap = 0;
541	    pline_The("lava now feels soothing.");
542	}
543	if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
544	    if (Punished) {
545		You("slip out of the iron chain.");
546		unpunish();
547	    }
548	}
549	if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) &&
550		(amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) ||
551		  (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) {
552	    You("are no longer stuck in the %s.",
553		    u.utraptype == TT_WEB ? "web" : "bear trap");
554	    /* probably should burn webs too if PM_FIRE_ELEMENTAL */
555	    u.utrap = 0;
556	}
557	if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) {
558	    You("orient yourself on the web.");
559	    u.utrap = 0;
560	}
561	flags.botl = 1;
562	vision_full_recalc = 1;
563	see_monsters();
564	exercise(A_CON, FALSE);
565	exercise(A_WIS, TRUE);
566	(void) encumber_msg();
567	return(1);
568}
569
570STATIC_OVL void
571break_armor()
572{
573    register struct obj *otmp;
574
575    if (breakarm(youmonst.data)) {
576	if ((otmp = uarm) != 0) {
577		if (donning(otmp)) cancel_don();
578		You("break out of your armor!");
579		exercise(A_STR, FALSE);
580		(void) Armor_gone();
581		useup(otmp);
582	}
583	if ((otmp = uarmc) != 0) {
584	    if(otmp->oartifact) {
585		Your("%s falls off!", cloak_simple_name(otmp));
586		(void) Cloak_off();
587		dropx(otmp);
588	    } else {
589		Your("%s tears apart!", cloak_simple_name(otmp));
590		(void) Cloak_off();
591		useup(otmp);
592	    }
593	}
594#ifdef TOURIST
595	if (uarmu) {
596		Your("shirt rips to shreds!");
597		useup(uarmu);
598	}
599#endif
600    } else if (sliparm(youmonst.data)) {
601	if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) {
602		if (donning(otmp)) cancel_don();
603		Your("armor falls around you!");
604		(void) Armor_gone();
605		dropx(otmp);
606	}
607	if ((otmp = uarmc) != 0) {
608		if (is_whirly(youmonst.data))
609			Your("%s falls, unsupported!", cloak_simple_name(otmp));
610		else You("shrink out of your %s!", cloak_simple_name(otmp));
611		(void) Cloak_off();
612		dropx(otmp);
613	}
614#ifdef TOURIST
615	if ((otmp = uarmu) != 0) {
616		if (is_whirly(youmonst.data))
617			You("seep right through your shirt!");
618		else You("become much too small for your shirt!");
619		setworn((struct obj *)0, otmp->owornmask & W_ARMU);
620		dropx(otmp);
621	}
622#endif
623    }
624    if (has_horns(youmonst.data)) {
625	if ((otmp = uarmh) != 0) {
626	    if (is_flimsy(otmp) && !donning(otmp)) {
627		char hornbuf[BUFSZ], yourbuf[BUFSZ];
628
629		/* Future possiblities: This could damage/destroy helmet */
630		Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data)));
631		Your("%s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"),
632		     shk_your(yourbuf, otmp), xname(otmp));
633	    } else {
634		if (donning(otmp)) cancel_don();
635		Your("helmet falls to the %s!", surface(u.ux, u.uy));
636		(void) Helmet_off();
637		dropx(otmp);
638	    }
639	}
640    }
641    if (nohands(youmonst.data) || verysmall(youmonst.data)) {
642	if ((otmp = uarmg) != 0) {
643	    if (donning(otmp)) cancel_don();
644	    /* Drop weapon along with gloves */
645	    You("drop your gloves%s!", uwep ? " and weapon" : "");
646	    drop_weapon(0);
647	    (void) Gloves_off();
648	    dropx(otmp);
649	}
650	if ((otmp = uarms) != 0) {
651	    You("can no longer hold your shield!");
652	    (void) Shield_off();
653	    dropx(otmp);
654	}
655	if ((otmp = uarmh) != 0) {
656	    if (donning(otmp)) cancel_don();
657	    Your("helmet falls to the %s!", surface(u.ux, u.uy));
658	    (void) Helmet_off();
659	    dropx(otmp);
660	}
661    }
662    if (nohands(youmonst.data) || verysmall(youmonst.data) ||
663		slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) {
664	if ((otmp = uarmf) != 0) {
665	    if (donning(otmp)) cancel_don();
666	    if (is_whirly(youmonst.data))
667		Your("boots fall away!");
668	    else Your("boots %s off your feet!",
669			verysmall(youmonst.data) ? "slide" : "are pushed");
670	    (void) Boots_off();
671	    dropx(otmp);
672	}
673    }
674}
675
676STATIC_OVL void
677drop_weapon(alone)
678int alone;
679{
680    struct obj *otmp;
681    struct obj *otmp2;
682
683    if ((otmp = uwep) != 0) {
684	/* !alone check below is currently superfluous but in the
685	 * future it might not be so if there are monsters which cannot
686	 * wear gloves but can wield weapons
687	 */
688	if (!alone || cantwield(youmonst.data)) {
689	    struct obj *wep = uwep;
690
691	    if (alone) You("find you must drop your weapon%s!",
692			   	u.twoweap ? "s" : "");
693	    otmp2 = u.twoweap ? uswapwep : 0;
694	    uwepgone();
695	    if (!wep->cursed || wep->otyp != LOADSTONE)
696		dropx(otmp);
697	    if (otmp2 != 0) {
698		uswapwepgone();
699		if (!otmp2->cursed || otmp2->otyp != LOADSTONE)
700		    dropx(otmp2);
701	    }
702	    untwoweapon();
703	} else if (!could_twoweap(youmonst.data)) {
704	    untwoweapon();
705	}
706    }
707}
708
709void
710rehumanize()
711{
712	/* You can't revert back while unchanging */
713	if (Unchanging && (u.mh < 1)) {
714		killer_format = NO_KILLER_PREFIX;
715		killer = "killed while stuck in creature form";
716		done(DIED);
717	}
718
719	if (emits_light(youmonst.data))
720	    del_light_source(LS_MONSTER, (genericptr_t)&youmonst);
721	polyman("return to %s form!", urace.adj);
722
723	if (u.uhp < 1) {
724	    char kbuf[256];
725
726	    Sprintf(kbuf, "reverting to unhealthy %s form", urace.adj);
727	    killer_format = KILLED_BY;
728	    killer = kbuf;
729	    done(DIED);
730	}
731	if (!uarmg) selftouch("No longer petrify-resistant, you");
732	nomul(0);
733
734	flags.botl = 1;
735	vision_full_recalc = 1;
736	(void) encumber_msg();
737}
738
739int
740dobreathe()
741{
742	struct attack *mattk;
743
744	if (Strangled) {
745	    You_cant("breathe.  Sorry.");
746	    return(0);
747	}
748	if (u.uen < 15) {
749	    You("don't have enough energy to breathe!");
750	    return(0);
751	}
752	u.uen -= 15;
753	flags.botl = 1;
754
755	if (!getdir((char *)0)) return(0);
756
757	mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY);
758	if (!mattk)
759	    impossible("bad breath attack?");	/* mouthwash needed... */
760	else
761	    buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn,
762		u.ux, u.uy, u.dx, u.dy);
763	return(1);
764}
765
766int
767dospit()
768{
769	struct obj *otmp;
770
771	if (!getdir((char *)0)) return(0);
772	otmp = mksobj(u.umonnum==PM_COBRA ? BLINDING_VENOM : ACID_VENOM,
773			TRUE, FALSE);
774	otmp->spe = 1; /* to indicate it's yours */
775	throwit(otmp, 0L, FALSE);
776	return(1);
777}
778
779int
780doremove()
781{
782	if (!Punished) {
783		You("are not chained to anything!");
784		return(0);
785	}
786	unpunish();
787	return(1);
788}
789
790int
791dospinweb()
792{
793	register struct trap *ttmp = t_at(u.ux,u.uy);
794
795	if (Levitation || Is_airlevel(&u.uz)
796	    || Underwater || Is_waterlevel(&u.uz)) {
797		You("must be on the ground to spin a web.");
798		return(0);
799	}
800	if (u.uswallow) {
801		You("release web fluid inside %s.", mon_nam(u.ustuck));
802		if (is_animal(u.ustuck->data)) {
803			expels(u.ustuck, u.ustuck->data, TRUE);
804			return(0);
805		}
806		if (is_whirly(u.ustuck->data)) {
807			int i;
808
809			for (i = 0; i < NATTK; i++)
810				if (u.ustuck->data->mattk[i].aatyp == AT_ENGL)
811					break;
812			if (i == NATTK)
813			       impossible("Swallower has no engulfing attack?");
814			else {
815				char sweep[30];
816
817				sweep[0] = '\0';
818				switch(u.ustuck->data->mattk[i].adtyp) {
819					case AD_FIRE:
820						Strcpy(sweep, "ignites and ");
821						break;
822					case AD_ELEC:
823						Strcpy(sweep, "fries and ");
824						break;
825					case AD_COLD:
826						Strcpy(sweep,
827						      "freezes, shatters and ");
828						break;
829				}
830				pline_The("web %sis swept away!", sweep);
831			}
832			return(0);
833		}		     /* default: a nasty jelly-like creature */
834		pline_The("web dissolves into %s.", mon_nam(u.ustuck));
835		return(0);
836	}
837	if (u.utrap) {
838		You("cannot spin webs while stuck in a trap.");
839		return(0);
840	}
841	exercise(A_DEX, TRUE);
842	if (ttmp) switch (ttmp->ttyp) {
843		case PIT:
844		case SPIKED_PIT: You("spin a web, covering up the pit.");
845			deltrap(ttmp);
846			bury_objs(u.ux, u.uy);
847			newsym(u.ux, u.uy);
848			return(1);
849		case SQKY_BOARD: pline_The("squeaky board is muffled.");
850			deltrap(ttmp);
851			newsym(u.ux, u.uy);
852			return(1);
853		case TELEP_TRAP:
854		case LEVEL_TELEP:
855		case MAGIC_PORTAL:
856			Your("webbing vanishes!");
857			return(0);
858		case WEB: You("make the web thicker.");
859			return(1);
860		case HOLE:
861		case TRAPDOOR:
862			You("web over the %s.",
863			    (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole");
864			deltrap(ttmp);
865			newsym(u.ux, u.uy);
866			return 1;
867		case ROLLING_BOULDER_TRAP:
868			You("spin a web, jamming the trigger.");
869			deltrap(ttmp);
870			newsym(u.ux, u.uy);
871			return(1);
872		case ARROW_TRAP:
873		case DART_TRAP:
874		case BEAR_TRAP:
875		case ROCKTRAP:
876		case FIRE_TRAP:
877		case LANDMINE:
878		case SLP_GAS_TRAP:
879		case RUST_TRAP:
880		case MAGIC_TRAP:
881		case ANTI_MAGIC:
882		case POLY_TRAP:
883			You("have triggered a trap!");
884			dotrap(ttmp, 0);
885			return(1);
886		default:
887			impossible("Webbing over trap type %d?", ttmp->ttyp);
888			return(0);
889		}
890	else if (On_stairs(u.ux, u.uy)) {
891	    /* cop out: don't let them hide the stairs */
892	    Your("web fails to impede access to the %s.",
893		 (levl[u.ux][u.uy].typ == STAIRS) ? "stairs" : "ladder");
894	    return(1);
895
896	}
897	ttmp = maketrap(u.ux, u.uy, WEB);
898	if (ttmp) {
899		ttmp->tseen = 1;
900		ttmp->madeby_u = 1;
901	}
902	newsym(u.ux, u.uy);
903	return(1);
904}
905
906int
907dosummon()
908{
909	int placeholder;
910	if (u.uen < 10) {
911	    You("lack the energy to send forth a call for help!");
912	    return(0);
913	}
914	u.uen -= 10;
915	flags.botl = 1;
916
917	You("call upon your brethren for help!");
918	exercise(A_WIS, TRUE);
919	if (!were_summon(youmonst.data, TRUE, &placeholder, (char *)0))
920		pline("But none arrive.");
921	return(1);
922}
923
924int
925dogaze()
926{
927	register struct monst *mtmp;
928	int looked = 0;
929	char qbuf[QBUFSZ];
930	int i;
931	uchar adtyp = 0;
932
933	for (i = 0; i < NATTK; i++) {
934	    if(youmonst.data->mattk[i].aatyp == AT_GAZE) {
935		adtyp = youmonst.data->mattk[i].adtyp;
936		break;
937	    }
938	}
939	if (adtyp != AD_CONF && adtyp != AD_FIRE) {
940	    impossible("gaze attack %d?", adtyp);
941	    return 0;
942	}
943
944
945	if (Blind) {
946	    You_cant("see anything to gaze at.");
947	    return 0;
948	}
949	if (u.uen < 15) {
950	    You("lack the energy to use your special gaze!");
951	    return(0);
952	}
953	u.uen -= 15;
954	flags.botl = 1;
955
956	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
957	    if (DEADMONSTER(mtmp)) continue;
958	    if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
959		looked++;
960		if (Invis && !perceives(mtmp->data))
961		    pline("%s seems not to notice your gaze.", Monnam(mtmp));
962		else if (mtmp->minvis && !See_invisible)
963		    You_cant("see where to gaze at %s.", Monnam(mtmp));
964		else if (mtmp->m_ap_type == M_AP_FURNITURE
965			|| mtmp->m_ap_type == M_AP_OBJECT) {
966		    looked--;
967		    continue;
968		} else if (flags.safe_dog && !Confusion && !Hallucination
969		  && mtmp->mtame) {
970		    You("avoid gazing at %s.", y_monnam(mtmp));
971		} else {
972		    if (flags.confirm && mtmp->mpeaceful && !Confusion
973							&& !Hallucination) {
974			Sprintf(qbuf, "Really %s %s?",
975			    (adtyp == AD_CONF) ? "confuse" : "attack",
976			    mon_nam(mtmp));
977			if (yn(qbuf) != 'y') continue;
978			setmangry(mtmp);
979		    }
980		    if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping ||
981				    !mtmp->mcansee || !haseyes(mtmp->data)) {
982			looked--;
983			continue;
984		    }
985		    /* No reflection check for consistency with when a monster
986		     * gazes at *you*--only medusa gaze gets reflected then.
987		     */
988		    if (adtyp == AD_CONF) {
989			if (!mtmp->mconf)
990			    Your("gaze confuses %s!", mon_nam(mtmp));
991			else
992			    pline("%s is getting more and more confused.",
993							Monnam(mtmp));
994			mtmp->mconf = 1;
995		    } else if (adtyp == AD_FIRE) {
996			int dmg = d(2,6);
997			You("attack %s with a fiery gaze!", mon_nam(mtmp));
998			if (resists_fire(mtmp)) {
999			    pline_The("fire doesn't burn %s!", mon_nam(mtmp));
1000			    dmg = 0;
1001			}
1002			if((int) u.ulevel > rn2(20))
1003			    (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
1004			if((int) u.ulevel > rn2(20))
1005			    (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
1006			if((int) u.ulevel > rn2(25))
1007			    (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
1008			if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg;
1009			if (mtmp->mhp <= 0) killed(mtmp);
1010		    }
1011		    /* For consistency with passive() in uhitm.c, this only
1012		     * affects you if the monster is still alive.
1013		     */
1014		    if (!DEADMONSTER(mtmp) &&
1015			  (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
1016			if (!Free_action) {
1017			    You("are frozen by %s gaze!",
1018					     s_suffix(mon_nam(mtmp)));
1019			    nomul((u.ulevel > 6 || rn2(4)) ?
1020				    -d((int)mtmp->m_lev+1,
1021					    (int)mtmp->data->mattk[0].damd)
1022				    : -200);
1023			    return 1;
1024			} else
1025			    You("stiffen momentarily under %s gaze.",
1026				    s_suffix(mon_nam(mtmp)));
1027		    }
1028		    /* Technically this one shouldn't affect you at all because
1029		     * the Medusa gaze is an active monster attack that only
1030		     * works on the monster's turn, but for it to *not* have an
1031		     * effect would be too weird.
1032		     */
1033		    if (!DEADMONSTER(mtmp) &&
1034			    (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) {
1035			pline(
1036			 "Gazing at the awake %s is not a very good idea.",
1037			    l_monnam(mtmp));
1038			/* as if gazing at a sleeping anything is fruitful... */
1039			You("turn to stone...");
1040			killer_format = KILLED_BY;
1041			killer = "deliberately meeting Medusa's gaze";
1042			done(STONING);
1043		    }
1044		}
1045	    }
1046	}
1047	if (!looked) You("gaze at no place in particular.");
1048	return 1;
1049}
1050
1051int
1052dohide()
1053{
1054	boolean ismimic = youmonst.data->mlet == S_MIMIC;
1055
1056	if (u.uundetected || (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) {
1057		You("are already hiding.");
1058		return(0);
1059	}
1060	if (ismimic) {
1061		/* should bring up a dialog "what would you like to imitate?" */
1062		youmonst.m_ap_type = M_AP_OBJECT;
1063		youmonst.mappearance = STRANGE_OBJECT;
1064	} else
1065		u.uundetected = 1;
1066	newsym(u.ux,u.uy);
1067	return(1);
1068}
1069
1070int
1071domindblast()
1072{
1073	struct monst *mtmp, *nmon;
1074
1075	if (u.uen < 10) {
1076	    You("concentrate but lack the energy to maintain doing so.");
1077	    return(0);
1078	}
1079	u.uen -= 10;
1080	flags.botl = 1;
1081
1082	You("concentrate.");
1083	pline("A wave of psychic energy pours out.");
1084	for(mtmp=fmon; mtmp; mtmp = nmon) {
1085		int u_sen;
1086
1087		nmon = mtmp->nmon;
1088		if (DEADMONSTER(mtmp))
1089			continue;
1090		if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM)
1091			continue;
1092		if(mtmp->mpeaceful)
1093			continue;
1094		u_sen = telepathic(mtmp->data) && !mtmp->mcansee;
1095		if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) {
1096			You("lock in on %s %s.", s_suffix(mon_nam(mtmp)),
1097				u_sen ? "telepathy" :
1098				telepathic(mtmp->data) ? "latent telepathy" :
1099				"mind");
1100			mtmp->mhp -= rnd(15);
1101			if (mtmp->mhp <= 0)
1102				killed(mtmp);
1103		}
1104	}
1105	return 1;
1106}
1107
1108STATIC_OVL void
1109uunstick()
1110{
1111	pline("%s is no longer in your clutches.", Monnam(u.ustuck));
1112	u.ustuck = 0;
1113}
1114
1115void
1116skinback(silently)
1117boolean silently;
1118{
1119	if (uskin) {
1120		if (!silently) Your("skin returns to its original form.");
1121		uarm = uskin;
1122		uskin = (struct obj *)0;
1123		/* undo save/restore hack */
1124		uarm->owornmask &= ~I_SPECIAL;
1125	}
1126}
1127
1128#endif /* OVLB */
1129#ifdef OVL1
1130
1131const char *
1132mbodypart(mon, part)
1133struct monst *mon;
1134int part;
1135{
1136	static NEARDATA const char
1137	*humanoid_parts[] = { "arm", "eye", "face", "finger",
1138		"fingertip", "foot", "hand", "handed", "head", "leg",
1139		"light headed", "neck", "spine", "toe", "hair",
1140		"blood", "lung", "nose", "stomach"},
1141	*jelly_parts[] = { "pseudopod", "dark spot", "front",
1142		"pseudopod extension", "pseudopod extremity",
1143		"pseudopod root", "grasp", "grasped", "cerebral area",
1144		"lower pseudopod", "viscous", "middle", "surface",
1145		"pseudopod extremity", "ripples", "juices",
1146		"surface", "sensor", "stomach" },
1147	*animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip",
1148		"rear claw", "foreclaw", "clawed", "head", "rear limb",
1149		"light headed", "neck", "spine", "rear claw tip",
1150		"fur", "blood", "lung", "nose", "stomach" },
1151	*bird_parts[] = { "wing", "eye", "face", "wing", "wing tip",
1152		"foot", "wing", "winged", "head", "leg",
1153		"light headed", "neck", "spine", "toe",
1154		"feathers", "blood", "lung", "bill", "stomach" },
1155	*horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip",
1156		"rear hoof", "foreclaw", "hooved", "head", "rear leg",
1157		"light headed", "neck", "backbone", "rear hoof tip",
1158		"mane", "blood", "lung", "nose", "stomach"},
1159	*sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle",
1160		"tentacle tip", "lower appendage", "tentacle", "tentacled",
1161		"body", "lower tentacle", "rotational", "equator", "body",
1162		"lower tentacle tip", "cilia", "life force", "retina",
1163		"olfactory nerve", "interior" },
1164	*fungus_parts[] = { "mycelium", "visual area", "front", "hypha",
1165		"hypha", "root", "strand", "stranded", "cap area",
1166		"rhizome", "sporulated", "stalk", "root", "rhizome tip",
1167		"spores", "juices", "gill", "gill", "interior" },
1168	*vortex_parts[] = { "region", "eye", "front", "minor current",
1169		"minor current", "lower current", "swirl", "swirled",
1170		"central core", "lower current", "addled", "center",
1171		"currents", "edge", "currents", "life force",
1172		"center", "leading edge", "interior" },
1173	*snake_parts[] = { "vestigial limb", "eye", "face", "large scale",
1174		"large scale tip", "rear region", "scale gap", "scale gapped",
1175		"head", "rear region", "light headed", "neck", "length",
1176		"rear scale", "scales", "blood", "lung", "forked tongue", "stomach" },
1177	*fish_parts[] = { "fin", "eye", "premaxillary", "pelvic axillary",
1178		"pelvic fin", "anal fin", "pectoral fin", "finned", "head", "peduncle",
1179		"played out", "gills", "dorsal fin", "caudal fin",
1180		"scales", "blood", "gill", "nostril", "stomach" };
1181	/* claw attacks are overloaded in mons[]; most humanoids with
1182	   such attacks should still reference hands rather than claws */
1183	static const char not_claws[] = {
1184		S_HUMAN, S_MUMMY, S_ZOMBIE, S_ANGEL,
1185		S_NYMPH, S_LEPRECHAUN, S_QUANTMECH, S_VAMPIRE,
1186		S_ORC, S_GIANT,		/* quest nemeses */
1187		'\0'		/* string terminator; assert( S_xxx != 0 ); */
1188	};
1189	struct permonst *mptr = mon->data;
1190
1191	if (part == HAND || part == HANDED) {	/* some special cases */
1192	    if (mptr->mlet == S_DOG || mptr->mlet == S_FELINE ||
1193		    mptr->mlet == S_YETI)
1194		return part == HAND ? "paw" : "pawed";
1195	    if (humanoid(mptr) && attacktype(mptr, AT_CLAW) &&
1196		    !index(not_claws, mptr->mlet) &&
1197		    mptr != &mons[PM_STONE_GOLEM] &&
1198		    mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS])
1199		return part == HAND ? "claw" : "clawed";
1200	}
1201	if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON]) &&
1202		part == NOSE)
1203	    return "trunk";
1204	if (mptr == &mons[PM_SHARK] && part == HAIR)
1205	    return "skin";	/* sharks don't have scales */
1206	if (mptr == &mons[PM_JELLYFISH] && (part == ARM || part == FINGER ||
1207	    part == HAND || part == FOOT || part == TOE))
1208	    return "tentacle";
1209	if (mptr == &mons[PM_FLOATING_EYE] && part == EYE)
1210	    return "cornea";
1211	if (humanoid(mptr) &&
1212		(part == ARM || part == FINGER || part == FINGERTIP ||
1213		    part == HAND || part == HANDED))
1214	    return humanoid_parts[part];
1215	if (mptr == &mons[PM_RAVEN])
1216	    return bird_parts[part];
1217	if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN ||
1218		(mptr == &mons[PM_ROTHE] && part != HAIR))
1219	    return horse_parts[part];
1220	if (mptr->mlet == S_LIGHT) {
1221		if (part == HANDED) return "rayed";
1222		else if (part == ARM || part == FINGER ||
1223				part == FINGERTIP || part == HAND) return "ray";
1224		else return "beam";
1225	}
1226	if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH])
1227	    return fish_parts[part];
1228	if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR))
1229	    return snake_parts[part];
1230	if (mptr->mlet == S_EYE)
1231	    return sphere_parts[part];
1232	if (mptr->mlet == S_JELLY || mptr->mlet == S_PUDDING ||
1233		mptr->mlet == S_BLOB || mptr == &mons[PM_JELLYFISH])
1234	    return jelly_parts[part];
1235	if (mptr->mlet == S_VORTEX || mptr->mlet == S_ELEMENTAL)
1236	    return vortex_parts[part];
1237	if (mptr->mlet == S_FUNGUS)
1238	    return fungus_parts[part];
1239	if (humanoid(mptr))
1240	    return humanoid_parts[part];
1241	return animal_parts[part];
1242}
1243
1244const char *
1245body_part(part)
1246int part;
1247{
1248	return mbodypart(&youmonst, part);
1249}
1250
1251#endif /* OVL1 */
1252#ifdef OVL0
1253
1254int
1255poly_gender()
1256{
1257/* Returns gender of polymorphed player; 0/1=same meaning as flags.female,
1258 * 2=none.
1259 */
1260	if (is_neuter(youmonst.data) || !humanoid(youmonst.data)) return 2;
1261	return flags.female;
1262}
1263
1264#endif /* OVL0 */
1265#ifdef OVLB
1266
1267void
1268ugolemeffects(damtype, dam)
1269int damtype, dam;
1270{
1271	int heal = 0;
1272	/* We won't bother with "slow"/"haste" since players do not
1273	 * have a monster-specific slow/haste so there is no way to
1274	 * restore the old velocity once they are back to human.
1275	 */
1276	if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM)
1277		return;
1278	switch (damtype) {
1279		case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM)
1280				heal = dam / 6; /* Approx 1 per die */
1281			break;
1282		case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM)
1283				heal = dam;
1284			break;
1285	}
1286	if (heal && (u.mh < u.mhmax)) {
1287		u.mh += heal;
1288		if (u.mh > u.mhmax) u.mh = u.mhmax;
1289		flags.botl = 1;
1290		pline("Strangely, you feel better than before.");
1291		exercise(A_STR, TRUE);
1292	}
1293}
1294
1295STATIC_OVL int
1296armor_to_dragon(atyp)
1297int atyp;
1298{
1299	switch(atyp) {
1300	    case GRAY_DRAGON_SCALE_MAIL:
1301	    case GRAY_DRAGON_SCALES:
1302		return PM_GRAY_DRAGON;
1303	    case SILVER_DRAGON_SCALE_MAIL:
1304	    case SILVER_DRAGON_SCALES:
1305		return PM_SILVER_DRAGON;
1306#if 0	/* DEFERRED */
1307	    case SHIMMERING_DRAGON_SCALE_MAIL:
1308	    case SHIMMERING_DRAGON_SCALES:
1309		return PM_SHIMMERING_DRAGON;
1310#endif
1311	    case RED_DRAGON_SCALE_MAIL:
1312	    case RED_DRAGON_SCALES:
1313		return PM_RED_DRAGON;
1314	    case ORANGE_DRAGON_SCALE_MAIL:
1315	    case ORANGE_DRAGON_SCALES:
1316		return PM_ORANGE_DRAGON;
1317	    case WHITE_DRAGON_SCALE_MAIL:
1318	    case WHITE_DRAGON_SCALES:
1319		return PM_WHITE_DRAGON;
1320	    case BLACK_DRAGON_SCALE_MAIL:
1321	    case BLACK_DRAGON_SCALES:
1322		return PM_BLACK_DRAGON;
1323	    case BLUE_DRAGON_SCALE_MAIL:
1324	    case BLUE_DRAGON_SCALES:
1325		return PM_BLUE_DRAGON;
1326	    case GREEN_DRAGON_SCALE_MAIL:
1327	    case GREEN_DRAGON_SCALES:
1328		return PM_GREEN_DRAGON;
1329	    case YELLOW_DRAGON_SCALE_MAIL:
1330	    case YELLOW_DRAGON_SCALES:
1331		return PM_YELLOW_DRAGON;
1332	    default:
1333		return -1;
1334	}
1335}
1336
1337#endif /* OVLB */
1338
1339/*polyself.c*/
1340