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