Difference between revisions of "Source:NetHack 3.4.3/src/polyself.c"

From NetHackWiki
Jump to navigation Jump to search
(newman: A pacifist asked rng whether it would be feasible to use "new elf" polymorph to gain experience levels. The source code suggests that this would not work.)
m (Polyself.c moved to Source:Polyself.c: Robot: moved page)
(No difference)

Revision as of 14:49, 4 March 2008

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

Top of file

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.    

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.

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.   

set_uasmon

23.   /* update the youmonst.data structure pointer */
24.   void
25.   set_uasmon()
26.   {
27.   	set_mon_data(&youmonst, &mons[u.umonnum], 0);
28.   }
29.   

polyman

30.   /* make a (new) human out of the player */
31.   STATIC_OVL void
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.   

change_sex

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 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.  

newman

131.  STATIC_OVL void
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.  

NetHack calls this function when you try to polymorph into your own race. This implements the "You feel like a new man!" (or elf) process, that permanently changes you into a physically different person.

There is nothing in this part of the source code to cure blindness (is this correct?) or to remove intrinsics that you gained from outside (for example by eating the corpse of a floating eye).

This process has curing effects, but for healthy adventurers, the DevTeam seems to have intentionally designed this function such that there is an equal chance that each adjustment is beneficial or harmful. As xanthian explains to rgrn, the expected value of the level change is zero. Because this function does not call rnl, the luck integer has no effect here. You also cannot use a unicorn horn or other such cure to regain any lost levels or attributes. The comment at line 144 explains how the source code adjusts your peak level to prevent this. The redist_attr function sets both your current and peak attributes, too. The becoming of a new man (or new gnome) many times is no way to raise your experience level or your attributes.

polyself

220.  void
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.  

polymon

328.  /* (try to) make a mntmp monster out of the player */
329.  int
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.  

break_armor

570.  STATIC_OVL void
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.  

drop_weapon

676.  STATIC_OVL void
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.  

rehumanize

709.  void
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.  

dobreathe

739.  int
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.  

dospit

766.  int
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.  

doremove

779.  int
780.  doremove()
781.  {
782.  	if (!Punished) {
783.  		You("are not chained to anything!");
784.  		return(0);
785.  	}
786.  	unpunish();
787.  	return(1);
788.  }
789.  

dospinweb

790.  int
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.  

dosummon

906.  int
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.  

dogaze

924.  int
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. 

dohide

1051. int
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. 

domindblast

1070. int
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. 

uunstick

1108. STATIC_OVL void
1109. uunstick()
1110. {
1111. 	pline("%s is no longer in your clutches.", Monnam(u.ustuck));
1112. 	u.ustuck = 0;
1113. }
1114. 

skinback

1115. void
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. 

mbodypart

1131. const char *
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. 

body_part

1244. const char *
1245. body_part(part)
1246. int part;
1247. {
1248. 	return mbodypart(&youmonst, part);
1249. }
1250. 
1251. #endif /* OVL1 */
1252. #ifdef OVL0
1253. 

body_part() returns a string describing a part of the hero's body; this depends on what kind of creature the hero currently is. Takes one parameter, one of the body part macros.

poly_gender

1254. int
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. 

ugolemeffects

1267. void
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. 

armor_to_dragon

1295. STATIC_OVL int
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*/