OSDN Git Service

rearrange main dungeon
[nethackexpress/trunk.git] / src / polyself.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1109 uunstick()
1110 {
1111         pline("%s is no longer in your clutches.", Monnam(u.ustuck));
1112         u.ustuck = 0;
1113 }
1114
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
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
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
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
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
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*/