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
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(uunstick);
20 STATIC_DCL int FDECL(armor_to_dragon,(int));
21 STATIC_DCL void NDECL(newman);
22 
23 /* update the youmonst.data structure pointer */
24 void
set_uasmon()25 set_uasmon()
26 {
27 	set_mon_data(&youmonst, &mons[u.umonnum], 0);
28 }
29 
30 /* make a (new) human out of the player */
31 STATIC_OVL void
polyman(fmt,arg)32 polyman(fmt, arg)
33 const 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 
99 void
change_sex()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 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 
131 STATIC_OVL void
newman()132 newman()
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 {
198 dead: /* 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 
220 void
polyself(forcecontrol)221 polyself(forcecontrol)
222 boolean 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 */
329 int
polymon(mntmp)330 polymon(mntmp)	/* returns 1 if polymorph successful */
331 int	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 
570 STATIC_OVL void
break_armor()571 break_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 
676 STATIC_OVL void
drop_weapon(alone)677 drop_weapon(alone)
678 int 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 
709 void
rehumanize()710 rehumanize()
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 
739 int
dobreathe()740 dobreathe()
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 
766 int
dospit()767 dospit()
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 
779 int
doremove()780 doremove()
781 {
782 	if (!Punished) {
783 		You("are not chained to anything!");
784 		return(0);
785 	}
786 	unpunish();
787 	return(1);
788 }
789 
790 int
dospinweb()791 dospinweb()
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 
906 int
dosummon()907 dosummon()
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 
924 int
dogaze()925 dogaze()
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 
1051 int
dohide()1052 dohide()
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 
1070 int
domindblast()1071 domindblast()
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 
1108 STATIC_OVL void
uunstick()1109 uunstick()
1110 {
1111 	pline("%s is no longer in your clutches.", Monnam(u.ustuck));
1112 	u.ustuck = 0;
1113 }
1114 
1115 void
skinback(silently)1116 skinback(silently)
1117 boolean 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 
1131 const char *
mbodypart(mon,part)1132 mbodypart(mon, part)
1133 struct monst *mon;
1134 int 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 
1244 const char *
body_part(part)1245 body_part(part)
1246 int part;
1247 {
1248 	return mbodypart(&youmonst, part);
1249 }
1250 
1251 #endif /* OVL1 */
1252 #ifdef OVL0
1253 
1254 int
poly_gender()1255 poly_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 
1267 void
ugolemeffects(damtype,dam)1268 ugolemeffects(damtype, dam)
1269 int 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 
1295 STATIC_OVL int
armor_to_dragon(atyp)1296 armor_to_dragon(atyp)
1297 int 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