Source:NetHack 3.0.0/polyself.c

From NetHackWiki
Revision as of 05:15, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.0.0/polyself.c moved to Source:NetHack 3.0.0/polyself.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to polyself.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.0/polyself.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)polyself.c	3.0	88/10/22
2.    /* Polymorph self routine.  Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    
7.    #ifdef POLYSELF
8.    
9.    static void break_armor(), drop_weapon();
10.   static void skinback();
11.   static void uunstick();
12.   
13.   void
14.   polyself()
15.   {
16.   	char buf[BUFSZ];
17.   	int tmp, tmp2, mntmp = -1;
18.   	int tries=0;
19.   	boolean draconian = (uarm && uarm->otyp==DRAGON_SCALE_MAIL &&
20.   		uarm->corpsenm >= PM_GREY_DRAGON &&
21.   		uarm->corpsenm <= PM_YELLOW_DRAGON);
22.   	/* We have to calculate sticky in multiple places since we might go
23.   	 * through any one of them without going through the others.
24.   	 */
25.   	boolean sticky = sticks(uasmon) && u.ustuck && !u.uswallow;
26.   
27.   	if(!Polymorph_control && !draconian) {
28.   	    if (rn2(20) > ACURR(A_CON)) {
29.   		You("shudder for a moment.");
30.   		losehp(rn2(30),"system shock");
31.   		return;
32.   	    }
33.   	}
34.   
35.   	if (Polymorph_control) {
36.   		do {
37.   			pline("Become what kind of monster? [type the name] ");
38.   			getlin(buf);
39.   			mntmp = name_to_mon(buf);
40.   			if (mntmp < 0)
41.   				pline("I've never heard of such monsters.");
42.   			else if (!polyok(&mons[mntmp]))
43.   				You("cannot polymorph into that.");
44.   			else break;
45.   		} while(++tries < 5);
46.   		if (tries==5) pline(thats_enough_tries);
47.   	} else if (draconian)
48.   		mntmp = uarm->corpsenm;
49.   
50.   	if (mntmp < 0) {
51.   		tries = 0;
52.   		do {
53.   			mntmp = rn2(PM_CHAMELEON);
54.   			/* All valid monsters are from 0 to PM_CHAMELEON-1 */
55.   		} while(!polyok(&mons[mntmp]) && tries++ < 200);
56.   	}
57.   
58.   	if (draconian && mntmp==uarm->corpsenm) {
59.   		if (!(mons[uarm->corpsenm].geno & G_GENOD)) {
60.   			You("merge with your scaly armor.");
61.   			uskin = uarm;
62.   			uarm = (struct obj *)0;
63.   		}
64.   	}
65.   	/* The below polyok() should never fail unless just about everything
66.   	 * was genocided...
67.   	 */
68.   	if (!polyok(&mons[mntmp]) || !rn2(5)) {
69.   		if (!rn2(10)) {
70.   			flags.female = !flags.female;
71.   			max_rank_sz();
72.   			if (pl_character[0]=='P')
73.   				Strcpy(pl_character+6, flags.female?"ess":"");
74.   			if (pl_character[0]=='C')
75.   				Strcpy(pl_character+5,
76.   				flags.female ? "woman" : "man");
77.   		}
78.   		if (u.umonnum != -1) {
79.   			u.acurr = u.macurr;	/* restore old attribs */
80.   			u.amax = u.mamax;
81.   		}
82.   	    tmp = u.uhpmax;
83.   	    tmp2 = u.ulevel;
84.   	    u.usym = S_HUMAN;
85.   	    u.umonnum = -1;
86.   	    if (u.uundetected) u.uundetected = 0;
87.   	    prme();
88.   	    u.mtimedone = u.mh = u.mhmax = 0;
89.   	    u.ulevel = u.ulevel-2+rn2(5);
90.   	    if (u.ulevel > 127 || u.ulevel == 0) u.ulevel = 1;
91.   	    if (u.ulevel > MAXULEV) u.ulevel = MAXULEV;
92.   
93.   	    for(tmp = u.ulevel; tmp != tmp2; tmp += (tmp2 < u.ulevel) ? -1 : 1)
94.   		adjabil((tmp2 > u.ulevel) ? -1 : 1);
95.   	    tmp = u.uhpmax;
96.   
97.   	    /* random experience points for the new experience level */
98.   	    u.uexp = rndexp();
99.   #ifndef LINT
100.  	    u.uhpmax = (u.uhpmax-10)*(long)u.ulevel/tmp2 + 19 - rn2(19);
101.  #endif
102.  /* If it was u.uhpmax*u.ulevel/tmp+9-rn2(19), then a 1st level character
103.     with 16 hp who polymorphed into a 3rd level one would have an average
104.     of 48 hp.  */
105.  #ifndef LINT
106.  	    u.uhp = u.uhp * (long)u.uhpmax/tmp;
107.  #endif
108.  #ifdef SPELLS
109.  	    tmp = u.uenmax;
110.  #ifndef LINT
111.  	    u.uenmax = u.uenmax * (long)u.ulevel/tmp2 + 9 - rn2(19);
112.  #endif
113.  	    if (u.uenmax < 0) u.uenmax = 0;
114.  #ifndef LINT
115.  	    u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax);
116.  #endif
117.  #endif
118.  	    (void)redist_attr();
119.  	    u.uhunger = rn1(500,500);
120.  	    Sick = 0;
121.  	    Stoned = 0;
122.  	    if (u.uhp <= 0 || u.uhpmax <= 0) {
123.  
124.  		if(Polymorph_control) {
125.  		    if (u.uhp <= 0) u.uhp = 1;
126.  		    if (u.uhpmax <= 0) u.uhpmax = 1;
127.  		} else {
128.  		    Your("new form doesn't seem healthy enough to survive.");
129.  		    killer="unsuccessful polymorph";
130.  		    done("died");
131.  		}
132.  	    }
133.  	    set_uasmon();
134.  	    You("feel like a new %sman!", flags.female ? "wo" : "");
135.  #ifdef WIZARD
136.  	    if(!wizard) {
137.  #endif
138.  newname:	more();
139.  		do {
140.  		    pline("What is your new name? ");
141.  		    getlin(buf);
142.  		} while (buf[0]=='\033' || buf[0]==0);
143.  		if (!strcmp(plname,buf)) {
144.  		    pline("That is the same as your old name!");
145.  		    goto newname;
146.  		}
147.  		(void)strncpy(plname, buf, sizeof(plname)-1);
148.  		Sprintf(SAVEF, "save/%d%s", getuid(), plname);
149.  		regularize(SAVEF+5);		/* avoid . or / in name */
150.  #ifdef WIZARD
151.  	    }
152.  #endif
153.  	    flags.botl = 1;
154.  	    skinback();
155.  	    find_ac();
156.  	    if (sticky) uunstick();
157.  	} else if(!polymon(mntmp)) return;
158.  
159.  	if (!uarmg) selftouch("No longer petrify-resistant, you");
160.  	if (Inhell && !Fire_resistance) {
161.  	    You("burn to a crisp.");
162.  	    killer = "unwise polymorph";
163.  	    done("burned");
164.  	}
165.  }
166.  
167.  int
168.  polymon(mntmp)	/* returns 1 if polymorph successful */
169.  	int	mntmp;
170.  {
171.  	int	tmp;
172.  	boolean sticky = sticks(uasmon) && u.ustuck && !u.uswallow;
173.  
174.  	if (mons[mntmp].geno & G_GENOD) {
175.  		You("feel rather %s-ish.",mons[mntmp].mname);
176.  		return(0);
177.  	}
178.  
179.  	if (u.umonnum == -1) {
180.  		/* Human to monster; save human stats */
181.  		u.macurr = u.acurr;
182.  		u.mamax = u.amax;
183.  	} else {
184.  		/* Monster to monster; restore human stats, to be
185.  		 * immediately changed to provide stats for the new monster
186.  		 */
187.  		u.acurr = u.macurr;
188.  		u.amax = u.mamax;
189.  	}
190.  	u.umonnum = mntmp;
191.  	set_uasmon();
192.  	u.usym = mons[mntmp].mlet;
193.  	/* New stats for monster, to last only as long as polymorphed.
194.  	 * Currently only strength gets changed.
195.  	 */
196.  	if(strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = 118;
197.  
198.  	if (resists_ston(uasmon) && Stoned) { /* parnes@eniac.seas.upenn.edu */
199.  		Stoned = 0;
200.  		You("no longer seem to be petrifying.");
201.  	}
202.  	if (u.usym == S_FUNGUS && Sick) {
203.  		Sick = 0;
204.  		You("no longer feel sick.");
205.  	}
206.  	if (u.usym == S_DRAGON && mntmp >= PM_GREY_DRAGON) u.mhmax = 80;
207.  #ifdef GOLEMS
208.  	else if (is_golem(uasmon)) u.mhmax = golemhp(mntmp);
209.  #endif /* GOLEMS */
210.  	else {
211.  
212.  		/*
213.  		tmp = adj_lev(&mons[mntmp]);
214.  		 * We can't do this, since there's no such thing as an
215.  		 * "experience level of you as a monster" for a polymorphed
216.  		 * character.
217.  		 */
218.  		tmp = mons[mntmp].mlevel;
219.  		if (!tmp) u.mhmax = rnd(4);
220.  		else u.mhmax = d(tmp, 8);
221.  	}
222.  	u.mh = u.mhmax;
223.  	You("turn into a%s %s!",
224.  		index(vowels, *(mons[mntmp].mname)) ? "n" : "",
225.  		mons[mntmp].mname);
226.  	if (uskin && mntmp != uskin->corpsenm)
227.  		skinback();
228.  	break_armor();
229.  	drop_weapon(1);
230.  	if (u.uundetected && !hides_under(uasmon)) u.uundetected = 0;
231.  	else if (hides_under(uasmon) && (levl[u.ux][u.uy].omask ||
232.  			levl[u.ux][u.uy].gmask))
233.  		u.uundetected = 1;
234.  	prme();
235.  	if (!sticky && !u.uswallow && u.ustuck && sticks(uasmon)) u.ustuck = 0;
236.  	else if (sticky && !sticks(uasmon)) uunstick();
237.  	u.mtimedone = 500 + rn2(500);
238.  	if (u.ulevel < mons[mntmp].mlevel)
239.  	/* Low level characters can't become high level monsters for long */
240.  		u.mtimedone = u.mtimedone * u.ulevel / mons[mntmp].mlevel;
241.  	flags.botl = 1;
242.  	if (can_breathe(uasmon))
243.  		pline("Use the command #monster for breath weapon.");
244.  	if (attacktype(uasmon, AT_SPIT))
245.  		pline("Use the command #monster to spit venom.");
246.  	if (u.usym == S_NYMPH)
247.  		pline("Use the command #monster if you have to remove an iron ball.");
248.  	if (u.usym == S_UMBER)
249.  		pline("Use the command #monster to confuse monsters.");
250.  	if (is_hider(uasmon))
251.  		pline("Use the command #monster to hide.");
252.  	if (is_were(uasmon))
253.  		pline("Use the command #monster to summon help.");
254.  	if (webmaker(uasmon))
255.  		pline("Use the command #monster to spin a web.");
256.  	if (lays_eggs(uasmon) || u.umonnum == PM_QUEEN_BEE)
257.  		pline("Use the command #sit to lay an egg.");
258.  	find_ac();
259.  	return(1);
260.  }
261.  
262.  static void
263.  break_armor() {
264.       struct obj *otmp;
265.  
266.       if (breakarm(uasmon)) {
267.  	if (otmp = uarm) {
268.  		You("break out of your armor!");
269.  		(void) Armor_gone();
270.  		useup(otmp);
271.  	}
272.  	if (otmp = uarmc) {
273.  		Your("cloak tears apart!");
274.  		(void) Cloak_off();
275.  		useup(otmp);
276.  	}
277.  #ifdef SHIRT
278.  	if (uarmu) {
279.  		Your("shirt rips to shreds!");
280.  		useup(uarmu);
281.  	}
282.  #endif
283.       } else if (sliparm(uasmon)) {
284.  	if (otmp = uarm) {
285.  		Your("armor falls around you!");
286.  		(void) Armor_gone();
287.  		dropx(otmp);
288.  	}
289.  	if (otmp = uarmc) {
290.  		You("shrink out of your cloak!");
291.  		(void) Cloak_off();
292.  		dropx(otmp);
293.  	}
294.  #ifdef SHIRT
295.  	if (otmp = uarmu) {
296.  		You("become much too small for your shirt!");
297.  		setworn((struct obj *)0, otmp->owornmask & W_ARMU);
298.  		dropx(otmp);
299.  	}
300.  #endif
301.       }
302.       if (nohands(uasmon) || verysmall(uasmon)) {
303.  	  if (otmp = uarmg) {
304.  	       /* Drop weapon along with gloves */
305.  	       You("drop your gloves%s!", uwep ? " and weapon" : "");
306.  	       (void) Gloves_off();
307.  	       dropx(otmp);
308.  	       drop_weapon(0);
309.  	  }
310.  	  if (otmp = uarms) {
311.  	       You("can no longer hold your shield!");
312.  	       (void) Shield_off();
313.  	       dropx(otmp);
314.  	  }
315.  	  if (otmp = uarmh) {
316.  	       Your("helmet falls to the floor!");
317.  	       (void) Helmet_off();
318.  	       dropx(otmp);
319.  	  }
320.  	  if (otmp = uarmf) {
321.  	       Your("boots %s off your feet!",
322.  			verysmall(uasmon) ? "slide" : "get pushed");
323.  	       (void) Boots_off();
324.  	       dropx(otmp);
325.  	  }
326.       }
327.  }
328.  
329.  static void
330.  drop_weapon(alone)
331.  int alone;
332.  {
333.       struct obj *otmp;
334.       if (otmp = uwep) {
335.  	  /* !alone check below is currently superfluous but in the
336.  	   * future it might not be so if there are monsters which cannot
337.  	   * wear gloves but can wield weapons
338.  	   */
339.  	  if (!alone || cantwield(uasmon)) {
340.  	       if (alone) You("find you must drop your weapon!");
341.  	       uwepgone();
342.  	       dropx(otmp);
343.  	  }
344.       }
345.  }
346.  
347.  void
348.  rehumanize()
349.  {
350.  	boolean sticky = sticks(uasmon) && u.ustuck && !u.uswallow;
351.  
352.  	u.mh = u.mhmax = u.mtimedone = 0;
353.   	u.acurr = u.macurr;		/* restore old strength */
354.   	u.amax = u.mamax;
355.  	u.usym = S_HUMAN;
356.  	u.umonnum = -1;
357.  	skinback();
358.  	set_uasmon();
359.  	You("return to %sn form!",(pl_character[0]=='E')?"elve":"huma");
360.  
361.  	if (u.uhp < 1)	done("died");
362.  	if (!Fire_resistance && Inhell) {
363.  	    You("burn to a crisp.");
364.  	    killer = "dissipating polymorph spell";
365.  	   done("burned");
366.  	}
367.  	if (!uarmg) selftouch("No longer petrify-resistant, you");
368.  	if (sticky) uunstick();
369.  	nomul(0);
370.  	if (u.uundetected) u.uundetected = 0;
371.  	prme();
372.  	flags.botl = 1;
373.  	find_ac();
374.  }
375.  
376.  int
377.  dobreathe() {
378.  	if(!getdir(1)) return(0);
379.  	if (rn2(4))
380.  	    You("produce a loud and noxious belch.");
381.  	else {
382.  	    register struct attack *mattk;
383.  	    register int i;
384.  
385.  	    for(i = 0; i < NATTK; i++) {
386.  		mattk = &(uasmon->mattk[i]);
387.  		if(mattk->aatyp == AT_BREA) break;
388.  	    }
389.  	    buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn,
390.  		u.ux, u.uy, u.dx, u.dy);
391.  	}
392.  	return(1);
393.  }
394.  
395.  int
396.  dospit() {
397.  	struct obj *otmp;
398.  
399.  	if (!getdir(1)) return(0);
400.  	otmp = mksobj(u.umonnum==PM_COBRA ? BLINDING_VENOM : ACID_VENOM, FALSE);
401.  	(void) throwit(otmp);
402.  	return(1);
403.  }
404.  
405.  int
406.  doremove() {
407.       if (!Punished) {
408.  	  You("are not chained to anything!");
409.  	  return(0);
410.       }
411.       unpunish();
412.       return(1);
413.  }
414.  
415.  int
416.  dospinweb() {
417.  	register struct trap *ttmp = t_at(u.ux,u.uy);
418.  
419.  	if (Levitation) {
420.  		You("must be on the ground to spin a web.");
421.  		return(0);
422.  	}
423.  	if (u.uswallow) {
424.  		You("release web fluid inside %s.", mon_nam(u.ustuck));
425.  		pline("%s regurgitates you!", Monnam(u.ustuck));
426.  		u.ux = u.ustuck->mx;
427.  		u.uy = u.ustuck->my;
428.  		mnexto(u.ustuck);
429.  		u.uswallow = 0;
430.  		u.ustuck = 0;
431.  		setsee();
432.  		docrt();
433.  		return(1);
434.  	}
435.  	if (u.utrap) {
436.  		You("cannot spin webs while stuck in a trap.");
437.  		return(0);
438.  	}
439.  	if (ttmp) switch (ttmp->ttyp) {
440.  		case SPIKED_PIT:
441.  		case PIT: You("spin a web, covering up the pit.");
442.  			deltrap(ttmp);
443.  			if (Invisible) newsym(u.ux, u.uy);
444.  			return(1);
445.  		case WEB: You("make the web thicker.");
446.  			return(1);
447.  		case SQBRD: pline("The squeaky board is muffled.");
448.  			deltrap(ttmp);
449.  			if (Invisible) newsym(u.ux, u.uy);
450.  			return(1);
451.  		case TELEP_TRAP:
452.  		case LEVEL_TELEP:
453.  			Your("webbing vanishes!");
454.  			return(0);
455.  		case TRAPDOOR: if (!is_maze_lev) {
456.  				You("web over the trapdoor.");
457.  				deltrap(ttmp);
458.  				if (Invisible) newsym(u.ux, u.uy);
459.  				return 1;
460.  			}
461.  			/* Fall through */
462.  		case MGTRP:
463.  		case POLY_TRAP:
464.  		case DART_TRAP:
465.  		case ARROW_TRAP:
466.  #ifdef SPELLS
467.  		case ANTI_MAGIC:
468.  #endif
469.  		case LANDMINE:
470.  		case SLP_GAS_TRAP:
471.  		case BEAR_TRAP:
472.  		case RUST_TRAP:
473.  			You("have triggered a trap!");
474.  			dotrap(ttmp);
475.  			return(1);
476.  		default:
477.  			impossible("Webbing over trap type %d?",ttmp->ttyp);
478.  			return(0);
479.  	}
480.  	ttmp = maketrap(u.ux, u.uy, WEB);
481.  	ttmp->tseen = 1;
482.  	if (Invisible) newsym(u.ux, u.uy);
483.  	return(1);
484.  }
485.  
486.  int
487.  dosummon()
488.  {
489.  	You("call upon your brethren for help!");
490.  	if (!were_summon(uasmon,TRUE))
491.  		pline("But none arrive.");
492.  	return(1);
493.  }
494.  
495.  int
496.  doconfuse()
497.  {
498.  	register struct monst *mtmp;
499.  	int looked = 0;
500.  
501.  	if (Blind) {
502.  		You("can't see anything to gaze at.");
503.  		return 0;
504.  	}
505.  	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
506.  	    if (canseemon(mtmp)) {
507.  		looked = 1;
508.  		if (Invis && !perceives(mtmp->data))
509.  		    pline("%s seems not to notice your gaze.", Monnam(mtmp));
510.  		else if (mtmp->minvis && !See_invisible)
511.  		    You("can't see where to gaze at %s.", Monnam(mtmp));
512.  		else if (mtmp->mimic)
513.  		    continue;
514.  		else if (flags.safe_dog && !Confusion && !Hallucination
515.  		  && (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_FELINE)
516.  		  && mtmp->mtame) {
517.  		    if (mtmp->mnamelth)
518.  			You("avoid gazing at %s.", NAME(mtmp));
519.  		    else
520.  			You("avoid gazing at your %s.",
521.  						mtmp->data->mname);
522.  		} else {
523.  		    if (flags.confirm && mtmp->mpeaceful && !Confusion
524.  							&& !Hallucination) {
525.  			pline("Really confuse %s? ", mon_nam(mtmp));
526.  			(void) fflush(stdout);
527.  			if (yn() != 'y') continue;
528.  			setmangry(mtmp);
529.  		    }
530.  		    if (mtmp->mfroz || mtmp->mstun || mtmp->msleep ||
531.  							mtmp->mblinded)
532.  			continue;
533.  		    if (!mtmp->mconf)
534.  			Your("gaze confuses %s!", mon_nam(mtmp));
535.  		    else
536.  			pline("%s is getting more and more confused.",
537.  							Monnam(mtmp));
538.  		    mtmp->mconf = 1;
539.  		    if ((mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
540.  			You("are frozen by %s's gaze!", mon_nam(mtmp));
541.  			nomul((u.ulevel > 6 || rn2(4)) ? 
542.  				-d((int)mtmp->m_lev+1,
543.  					(int)mtmp->data->mattk[0].damd)
544.  				: -200);
545.  			return 1;
546.  		    }
547.  #ifdef MEDUSA
548.  		    if ((mtmp->data==&mons[PM_MEDUSA]) && !mtmp->mcan) {
549.  			pline("Gazing at an awake medusa is not a very good idea...");
550.  			You("turn to stone...");
551.  			done("stoned");
552.  		    }
553.  #endif
554.  		}
555.  	    }
556.  	}
557.  	if (!looked) You("gaze at no place in particular.");
558.  	return 1;
559.  }
560.  
561.  int
562.  dohide()
563.  {
564.  	if (u.uundetected || u.usym == S_MIMIC_DEF) {
565.  		pline("You are already hiding.");
566.  		return(0);
567.  	}
568.  	if (u.usym == S_MIMIC) {
569.  		u.usym = S_MIMIC_DEF;
570.  		prme();
571.  	} else {
572.  		newsym(u.ux,u.uy);
573.  		u.uundetected = 1;
574.  	}
575.  	return(1);
576.  }
577.  
578.  static void
579.  uunstick()
580.  {
581.  	kludge("%s is no longer in your clutches...", Monnam(u.ustuck));
582.  	u.ustuck = 0;
583.  }
584.  
585.  static void
586.  skinback()
587.  {
588.  	if (uskin) {
589.  		Your("skin returns to its original form.");
590.  		uarm = uskin;
591.  		uskin = (struct obj *)0;
592.  	}	
593.  }
594.  #endif
595.  
596.  char *
597.  body_part(part)
598.  {
599.  	/* Note: it is assumed these will never be >22 characters long,
600.  	 * plus the trailing null, after pluralizing (since sometimes a
601.  	 * buffer is made a fixed size and must be able to hold it)
602.  	 */
603.  	static const char *humanoid_parts[] = { "arm", "eye", "face", "finger",
604.  		"fingertip", "foot", "hand", "handed", "head", "leg",
605.  		"light headed", "neck", "toe" };
606.  #ifdef POLYSELF
607.  	static const char *jelly_parts[] = { "pseudopod", "dark spot", "front",
608.  		"pseudopod extension", "pseudopod extremity",
609.  		"pseudopod root", "grasp", "grasped", "cerebral area",
610.  		"lower pseudopod", "viscous", "middle",
611.  		"pseudopod extremity" },
612.  	*animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip",
613.  		"rear claw", "foreclaw", "clawed", "head", "rear limb",
614.  		"light headed", "neck", "rear claw tip" },
615.  	*horse_parts[] = { "forelimb", "eye", "face", "forehoof", "hoof tip",
616.  		"rear hoof", "foreclaw", "hooved", "head", "rear limb",
617.  		"light headed", "neck", "rear hoof tip" },
618.  	*sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle",
619.  		"tentacle tip", "lower appendage", "tentacle", "tentacled",
620.  		"body", "lower tentacle", "rotational", "equator",
621.  		"lower tentacle tip" },
622.  	*fungus_parts[] = { "mycelium", "visual area", "front", "hypha",
623.  		"hypha", "root", "strand", "stranded", "cap area",
624.  		"rhizome", "sporulated", "stalk", "rhizome tip" },
625.  	*vortex_parts[] = { "region", "eye", "front", "minor current",
626.  		"minor current", "lower current", "swirl", "swirled",
627.  		"central core", "lower current", "addled", "center",
628.  		"edge" },
629.  	*snake_parts[] = { "vestigal limb", "eye", "face", "large scale",
630.  		"large scale tip", "rear region", "scale gap", "scale gapped",
631.  		"head", "rear region", "light headed", "neck", "rear scale" };
632.  	
633.  	if (humanoid(uasmon) || (u.usym==S_CENTAUR && 
634.  		(part==ARM || part==FINGER || part==FINGERTIP
635.  		|| part==HAND || part==HANDED))) return humanoid_parts[part];
636.  	if (u.usym==S_CENTAUR || u.usym==S_UNICORN) return horse_parts[part];
637.  	if (u.usym==S_SNAKE || u.usym==S_NAGA || u.usym==S_WORM)
638.  		return snake_parts[part];
639.  	if (u.usym==S_EYE) return sphere_parts[part];
640.  	if (u.usym==S_JELLY || u.usym==S_PUDDING) return jelly_parts[part];
641.  	if (u.usym==S_VORTEX || u.usym==S_ELEMENTAL) return vortex_parts[part];
642.  	if (u.usym==S_FUNGUS) return fungus_parts[part];
643.  	return animal_parts[part];
644.  #else
645.  	return humanoid_parts[part];
646.  #endif
647.  }
648.  
649.  int
650.  poly_gender()
651.  {
652.  /* Returns gender of polymorphed player; 0/1=same meaning as flags.female,
653.   * 2=none.
654.   * Used in:
655.   *	- Seduction by succubus/incubus
656.   *	- Talking to nymphs (sounds.c)
657.   * Not used in:
658.   *	- Messages given by nymphs stealing armor (they can't steal from
659.   *	  incubi/succubi/nymphs, and nonhumanoids can't wear armor).
660.   *	- Amulet of change (must refer to real gender no matter what
661.   *	  polymorphed into).
662.   *	- Priest/Priestess, Caveman/Cavewoman (ditto)
663.   *	- Polymorph self (only happens when human)
664.   *	- Shopkeeper messages (since referred to as "creature" and not "sir"
665.   *	  or "lady" when polymorphed)
666.   */
667.  #ifdef POLYSELF
668.  	if (uasmon->mflags1 & M1_FEM) return 1;
669.  #ifdef HARD
670.  	if (u.umonnum==PM_INCUBUS) return 0;
671.  #endif
672.  	if (!humanoid(uasmon)) return 2;
673.  #endif
674.  	return flags.female;
675.  }
676.  
677.  #ifdef POLYSELF
678.  #ifdef GOLEMS
679.  void
680.  ugolemeffects(damtype, dam)
681.  int damtype;
682.  {
683.  	int heal = 0;
684.  	/* We won't bother with "slow"/"haste" since players do not
685.  	 * have a monster-specific slow/haste so there is no way to
686.  	 * restore the old velocity once they are back to human.
687.  	 */
688.  	if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM)
689.  		return;
690.  	switch (damtype) {
691.  		case AD_ELEC: if (u.umonnum == PM_IRON_GOLEM)
692.  				heal = dam / 6; /* Approx 1 per die */
693.  			break;
694.  		case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM)
695.  				heal = dam;
696.  			break;
697.  	}
698.  	if (heal && (u.mh < u.mhmax)) {
699.  		u.mh += heal;
700.  		if (u.mh > u.mhmax) u.mh = u.mhmax;
701.  		flags.botl = 1;
702.  		pline("Strangely, you feel better than before.");
703.  	}
704.  }
705.  #endif /* GOLEMS */
706.  #endif