1 /* NetHack 3.6 polyself.c $NHDT-Date: 1448496566 2015/11/26 00:09:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.104 $ */
2 /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
3 /* NetHack may be freely redistributed. See license for details. */
6 * Polymorph self routine.
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.
12 * Transformation sequences:
13 * /-> polymon poly into monster form
15 * \-> newman -> polyman fail to poly, get human form
17 * rehumanize -> polyman return to original form
19 * polymon (called directly) usually golem petrification
24 STATIC_DCL
void FDECL(check_strangling
, (BOOLEAN_P
));
25 STATIC_DCL
void FDECL(polyman
, (const char *, const char *));
26 STATIC_DCL
void NDECL(break_armor
);
27 STATIC_DCL
void FDECL(drop_weapon
, (int));
28 STATIC_DCL
void NDECL(uunstick
);
29 STATIC_DCL
int FDECL(armor_to_dragon
, (int));
30 STATIC_DCL
void NDECL(newman
);
31 STATIC_DCL boolean
FDECL(polysense
, (struct permonst
*));
33 STATIC_VAR
const char no_longer_petrify_resistant
[] =
34 "No longer petrify-resistant, you";
36 /* controls whether taking on new form or becoming new man can also
37 change sex (ought to be an arg to polymon() and newman() instead) */
38 STATIC_VAR
int sex_change_ok
= 0;
40 /* update the youmonst.data structure pointer and intrinsics */
44 struct permonst
*mdat
= &mons
[u
.umonnum
];
46 set_mon_data(&youmonst
, mdat
, 0);
48 #define PROPSET(PropIndx, ON) \
51 u.uprops[PropIndx].intrinsic |= FROMFORM; \
53 u.uprops[PropIndx].intrinsic &= ~FROMFORM; \
56 PROPSET(FIRE_RES
, resists_fire(&youmonst
));
57 PROPSET(COLD_RES
, resists_cold(&youmonst
));
58 PROPSET(SLEEP_RES
, resists_sleep(&youmonst
));
59 PROPSET(DISINT_RES
, resists_disint(&youmonst
));
60 PROPSET(SHOCK_RES
, resists_elec(&youmonst
));
61 PROPSET(POISON_RES
, resists_poison(&youmonst
));
62 PROPSET(ACID_RES
, resists_acid(&youmonst
));
63 PROPSET(STONE_RES
, resists_ston(&youmonst
));
65 /* resists_drli() takes wielded weapon into account; suppress it */
66 struct obj
*save_uwep
= uwep
;
69 PROPSET(DRAIN_RES
, resists_drli(&youmonst
));
72 /* resists_magm() takes wielded, worn, and carried equipment into
73 into account; cheat and duplicate its monster-specific part */
74 PROPSET(ANTIMAGIC
, (dmgtype(mdat
, AD_MAGM
)
75 || mdat
== &mons
[PM_BABY_GRAY_DRAGON
]
76 || dmgtype(mdat
, AD_RBRE
)));
77 PROPSET(SICK_RES
, (mdat
->mlet
== S_FUNGUS
|| mdat
== &mons
[PM_GHOUL
]));
79 PROPSET(STUNNED
, (mdat
== &mons
[PM_STALKER
] || is_bat(mdat
)));
80 PROPSET(HALLUC_RES
, dmgtype(mdat
, AD_HALU
));
81 PROPSET(SEE_INVIS
, perceives(mdat
));
82 PROPSET(TELEPAT
, telepathic(mdat
));
83 PROPSET(INFRAVISION
, infravision(mdat
));
84 PROPSET(INVIS
, pm_invisible(mdat
));
85 PROPSET(TELEPORT
, can_teleport(mdat
));
86 PROPSET(TELEPORT_CONTROL
, control_teleport(mdat
));
87 PROPSET(LEVITATION
, is_floater(mdat
));
88 PROPSET(FLYING
, is_flyer(mdat
));
89 PROPSET(SWIMMING
, is_swimmer(mdat
));
90 /* [don't touch MAGICAL_BREATHING here; both Amphibious and Breathless
91 key off of it but include different monster forms...] */
92 PROPSET(PASSES_WALLS
, passes_walls(mdat
));
93 PROPSET(REGENERATION
, regenerates(mdat
));
94 PROPSET(REFLECTING
, (mdat
== &mons
[PM_SILVER_DRAGON
]));
96 float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
100 #ifdef STATUS_VIA_WINDOWPORT
101 status_initialize(REASSESS_ONLY
);
105 /* Levitation overrides Flying; set or clear BFlying|I_SPECIAL */
109 /* floating overrides flight; normally float_up() and float_down()
110 handle this, but sometimes they're skipped */
111 if (HLevitation
|| ELevitation
)
112 BFlying
|= I_SPECIAL
;
114 BFlying
&= ~I_SPECIAL
;
117 /* for changing into form that's immune to strangulation */
122 /* on -- maybe resume strangling */
124 /* when Strangled is already set, polymorphing from one
125 vulnerable form into another causes the counter to be reset */
126 if (uamul
&& uamul
->otyp
== AMULET_OF_STRANGULATION
127 && can_be_strangled(&youmonst
)) {
128 Your("%s %s your %s!", simpleonames(uamul
),
129 Strangled
? "still constricts" : "begins constricting",
130 body_part(NECK
)); /* "throat" */
132 makeknown(AMULET_OF_STRANGULATION
);
135 /* off -- maybe block strangling */
137 if (Strangled
&& !can_be_strangled(&youmonst
)) {
139 You("are no longer being strangled.");
144 /* make a (new) human out of the player */
147 const char *fmt
, *arg
;
149 boolean sticky
= (sticks(youmonst
.data
) && u
.ustuck
&& !u
.uswallow
),
150 was_mimicking
= (youmonst
.m_ap_type
== M_AP_OBJECT
);
151 boolean was_blind
= !!Blind
;
154 u
.acurr
= u
.macurr
; /* restore old attribs */
156 u
.umonnum
= u
.umonster
;
157 flags
.female
= u
.mfemale
;
172 youmonst
.m_ap_type
= M_AP_NOTHING
;
178 /* check whether player foolishly genocided self while poly'd */
179 if ((mvitals
[urole
.malenum
].mvflags
& G_GENOD
)
180 || (urole
.femalenum
!= NON_PM
181 && (mvitals
[urole
.femalenum
].mvflags
& G_GENOD
))
182 || (mvitals
[urace
.malenum
].mvflags
& G_GENOD
)
183 || (urace
.femalenum
!= NON_PM
184 && (mvitals
[urace
.femalenum
].mvflags
& G_GENOD
))) {
185 /* intervening activity might have clobbered genocide info */
186 struct kinfo
*kptr
= find_delayed_killer(POLYMORPH
);
188 if (kptr
!= (struct kinfo
*) 0 && kptr
->name
[0]) {
189 killer
.format
= kptr
->format
;
190 Strcpy(killer
.name
, kptr
->name
);
192 killer
.format
= KILLED_BY
;
193 Strcpy(killer
.name
, "self-genocide");
195 dealloc_killer(kptr
);
199 if (u
.twoweap
&& !could_twoweap(youmonst
.data
))
202 if (u
.utraptype
== TT_PIT
&& u
.utrap
) {
203 u
.utrap
= rn1(6, 2); /* time to escape resets */
205 if (was_blind
&& !Blind
) { /* reverting from eyeless */
207 make_blinded(0L, TRUE
); /* remove blindness */
209 check_strangling(TRUE
);
211 if (!Levitation
&& !u
.ustuck
&& is_pool_or_lava(u
.ux
, u
.uy
))
220 /* setting u.umonster for caveman/cavewoman or priest/priestess
221 swap unintentionally makes `Upolyd' appear to be true */
222 boolean already_polyd
= (boolean
) Upolyd
;
224 /* Some monsters are always of one sex and their sex can't be changed;
225 * Succubi/incubi can change, but are handled below.
227 * !already_polyd check necessary because is_male() and is_female()
228 * are true if the player is a priest/priestess.
231 || (!is_male(youmonst
.data
) && !is_female(youmonst
.data
)
232 && !is_neuter(youmonst
.data
)))
233 flags
.female
= !flags
.female
;
234 if (already_polyd
) /* poly'd: also change saved sex */
235 u
.mfemale
= !u
.mfemale
;
236 max_rank_sz(); /* [this appears to be superfluous] */
237 if ((already_polyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
238 Strcpy(pl_character
, urole
.name
.f
);
240 Strcpy(pl_character
, urole
.name
.m
);
241 u
.umonster
= ((already_polyd
? u
.mfemale
: flags
.female
)
242 && urole
.femalenum
!= NON_PM
)
245 if (!already_polyd
) {
246 u
.umonnum
= u
.umonster
;
247 } else if (u
.umonnum
== PM_SUCCUBUS
|| u
.umonnum
== PM_INCUBUS
) {
248 flags
.female
= !flags
.female
;
249 /* change monster type to match new sex */
250 u
.umonnum
= (u
.umonnum
== PM_SUCCUBUS
) ? PM_INCUBUS
: PM_SUCCUBUS
;
258 int i
, oldlvl
, newlvl
, hpmax
, enmax
;
261 newlvl
= oldlvl
+ rn1(5, -2); /* new = old + {-2,-1,0,+1,+2} */
262 if (newlvl
> 127 || newlvl
< 1) { /* level went below 0? */
263 goto dead
; /* old level is still intact (in case of lifesaving) */
265 if (newlvl
> MAXULEV
)
267 /* If your level goes down, your peak level goes down by
268 the same amount so that you can't simply use blessed
269 full healing to undo the decrease. But if your level
270 goes up, your peak level does *not* undergo the same
271 adjustment; you might end up losing out on the chance
272 to regain some levels previously lost to other causes. */
274 u
.ulevelmax
-= (oldlvl
- newlvl
);
275 if (u
.ulevelmax
< newlvl
)
276 u
.ulevelmax
= newlvl
;
279 if (sex_change_ok
&& !rn2(10))
282 adjabil(oldlvl
, (int) u
.ulevel
);
283 reset_rndmonst(NON_PM
); /* new monster generation criteria */
285 /* random experience points for the new experience level */
286 u
.uexp
= rndexp(FALSE
);
288 /* set up new attribute points (particularly Con) */
293 * remove level-gain based HP from any extra HP accumulated
294 * (the "extra" might actually be negative);
295 * modify the extra, retaining {80%, 90%, 100%, or 110%};
296 * add in newly generated set of level-gain HP.
298 * (This used to calculate new HP in direct proportion to old HP,
299 * but that was subject to abuse: accumulate a large amount of
300 * extra HP, drain level down to 1, then polyself to level 2 or 3
301 * [lifesaving capability needed to handle level 0 and -1 cases]
302 * and the extra got multiplied by 2 or 3. Repeat the level
303 * drain and polyself steps until out of lifesaving capability.)
306 for (i
= 0; i
< oldlvl
; i
++)
307 hpmax
-= (int) u
.uhpinc
[i
];
308 /* hpmax * rn1(4,8) / 10; 0.95*hpmax on average */
309 hpmax
= rounddiv((long) hpmax
* (long) rn1(4, 8), 10);
310 for (i
= 0; (u
.ulevel
= i
) < newlvl
; i
++)
312 if (hpmax
< u
.ulevel
)
313 hpmax
= u
.ulevel
; /* min of 1 HP per level */
314 /* retain same proportion for current HP; u.uhp * hpmax / u.uhpmax */
315 u
.uhp
= rounddiv((long) u
.uhp
* (long) hpmax
, u
.uhpmax
);
318 * Do the same for spell power.
321 for (i
= 0; i
< oldlvl
; i
++)
322 enmax
-= (int) u
.ueninc
[i
];
323 enmax
= rounddiv((long) enmax
* (long) rn1(4, 8), 10);
324 for (i
= 0; (u
.ulevel
= i
) < newlvl
; i
++)
326 if (enmax
< u
.ulevel
)
328 u
.uen
= rounddiv((long) u
.uen
* (long) enmax
,
329 ((u
.uenmax
< 1) ? 1 : u
.uenmax
));
331 /* [should alignment record be tweaked too?] */
333 u
.uhunger
= rn1(500, 500);
335 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
337 make_stoned(0L, (char *) 0, 0, (char *) 0);
339 if (Polymorph_control
) { /* even when Stunned || Unaware */
343 dead
: /* we come directly here if their experience level went to 0 or
345 Your("new form doesn't seem healthy enough to survive.");
346 killer
.format
= KILLED_BY_AN
;
347 Strcpy(killer
.name
, "unsuccessful polymorph");
350 (void) polysense(youmonst
.data
);
351 return; /* lifesaved */
355 polyman("feel like a new %s!",
356 /* use saved gender we're about to revert to, not current */
357 (u
.mfemale
&& urace
.individual
.f
)
359 : (urace
.individual
.m
) ? urace
.individual
.m
: urace
.noun
);
361 Your("body transforms, but there is still slime on you.");
362 make_slimed(10L, (const char *) 0);
365 (void) polysense(youmonst
.data
);
368 (void) encumber_msg();
370 retouch_equipment(2);
372 selftouch(no_longer_petrify_resistant
);
380 int old_light
, new_light
, mntmp
, class, tryct
;
381 boolean forcecontrol
= (psflags
== 1), monsterpoly
= (psflags
== 2),
382 draconian
= (uarm
&& Is_dragon_armor(uarm
)),
383 iswere
= (u
.ulycn
>= LOW_PM
), isvamp
= is_vampire(youmonst
.data
),
384 controllable_poly
= Polymorph_control
&& !(Stunned
|| Unaware
);
387 pline("You fail to transform!");
390 /* being Stunned|Unaware doesn't negate this aspect of Poly_control */
391 if (!Polymorph_control
&& !forcecontrol
&& !draconian
&& !iswere
393 if (rn2(20) > ACURR(A_CON
)) {
394 You1(shudder_for_moment
);
395 losehp(rnd(30), "system shock", KILLED_BY_AN
);
396 exercise(A_CON
, FALSE
);
400 old_light
= emits_light(youmonst
.data
);
403 if (monsterpoly
&& isvamp
)
406 if (controllable_poly
|| forcecontrol
) {
410 getlin("Become what kind of monster? [type the name]", buf
);
411 (void) mungspaces(buf
);
412 if (*buf
== '\033') {
413 /* user is cancelling controlled poly */
414 if (forcecontrol
) { /* wizard mode #polyself */
418 Strcpy(buf
, "*"); /* resort to random */
420 if (!strcmp(buf
, "*") || !strcmp(buf
, "random")) {
421 /* explicitly requesting random result */
422 tryct
= 0; /* will skip thats_enough_tries */
423 continue; /* end do-while(--tryct > 0) loop */
426 mntmp
= name_to_mon(buf
);
427 if (mntmp
< LOW_PM
) {
429 class = name_to_monclass(buf
, &mntmp
);
430 if (class && mntmp
== NON_PM
)
431 mntmp
= mkclass_poly(class);
433 if (mntmp
< LOW_PM
) {
435 pline("I've never heard of such monsters.");
437 You_cant("polymorph into any of those.");
438 } else if (iswere
&& (were_beastie(mntmp
) == u
.ulycn
439 || mntmp
== counter_were(u
.ulycn
)
440 || (Upolyd
&& mntmp
== PM_HUMAN
))) {
442 /* Note: humans are illegal as monsters, but an
443 * illegal monster forces newman(), which is what we
444 * want if they specified a human.... */
445 } else if (!polyok(&mons
[mntmp
])
446 && !(mntmp
== PM_HUMAN
|| your_race(&mons
[mntmp
])
447 || mntmp
== urole
.malenum
448 || mntmp
== urole
.femalenum
)) {
451 /* mkclass_poly() can pick a !polyok()
452 candidate; if so, usually try again */
454 if (rn2(3) || --tryct
> 0)
456 /* no retries left; put one back on counter
457 so that end of loop decrement will yield
458 0 and trigger thats_enough_tries message */
461 pm_name
= mons
[mntmp
].mname
;
462 if (the_unique_pm(&mons
[mntmp
]))
463 pm_name
= the(pm_name
);
464 else if (!type_is_pname(&mons
[mntmp
]))
465 pm_name
= an(pm_name
);
466 You_cant("polymorph into %s.", pm_name
);
469 } while (--tryct
> 0);
471 pline1(thats_enough_tries
);
472 /* allow skin merging, even when polymorph is controlled */
473 if (draconian
&& (tryct
<= 0 || mntmp
== armor_to_dragon(uarm
->otyp
)))
475 if (isvamp
&& (tryct
<= 0 || mntmp
== PM_WOLF
|| mntmp
== PM_FOG_CLOUD
476 || is_bat(&mons
[mntmp
])))
478 } else if (draconian
|| iswere
|| isvamp
) {
479 /* special changes that don't require polyok() */
482 mntmp
= armor_to_dragon(uarm
->otyp
);
483 if (!(mvitals
[mntmp
].mvflags
& G_GENOD
)) {
484 /* allow G_EXTINCT */
485 if (Is_dragon_scales(uarm
)) {
486 /* dragon scales remain intact as uskin */
487 You("merge with your scaly armor.");
488 } else { /* dragon scale mail */
489 /* d.scale mail first reverts to scales */
492 /* similar to noarmor(invent.c),
493 shorten to "<color> scale mail" */
494 dsmail
= strcpy(buf
, simpleonames(uarm
));
495 if ((p
= strstri(dsmail
, " dragon ")) != 0)
496 while ((p
[1] = p
[8]) != '\0')
498 /* tricky phrasing; dragon scale mail
499 is singular, dragon scales are plural */
500 Your("%s reverts to scales as you merge with them.",
502 /* uarm->spe enchantment remains unchanged;
503 re-converting scales to mail poses risk
504 of evaporation due to over enchanting */
505 uarm
->otyp
+= GRAY_DRAGON_SCALES
- GRAY_DRAGON_SCALE_MAIL
;
507 context
.botl
= 1; /* AC is changing */
510 uarm
= (struct obj
*) 0;
511 /* save/restore hack */
512 uskin
->owornmask
|= I_SPECIAL
;
517 if (Upolyd
&& were_beastie(mntmp
) != u
.ulycn
)
518 mntmp
= PM_HUMAN
; /* Illegal; force newman() */
523 if (mntmp
< LOW_PM
|| (mons
[mntmp
].geno
& G_UNIQ
))
524 mntmp
= (youmonst
.data
!= &mons
[PM_VAMPIRE
] && !rn2(10))
526 : !rn2(4) ? PM_FOG_CLOUD
: PM_VAMPIRE_BAT
;
527 if (controllable_poly
) {
528 Sprintf(buf
, "Become %s?", an(mons
[mntmp
].mname
));
533 /* if polymon fails, "you feel" message has been given
534 so don't follow up with another polymon or newman;
535 sex_change_ok left disabled here */
536 if (mntmp
== PM_HUMAN
)
537 newman(); /* werecritter */
539 (void) polymon(mntmp
);
540 goto made_change
; /* maybe not, but this is right anyway */
543 if (mntmp
< LOW_PM
) {
546 /* randomly pick an "ordinary" monster */
547 mntmp
= rn1(SPECIAL_PM
- LOW_PM
, LOW_PM
);
548 if (polyok(&mons
[mntmp
]) && !is_placeholder(&mons
[mntmp
]))
550 } while (--tryct
> 0);
553 /* The below polyok() fails either if everything is genocided, or if
554 * we deliberately chose something illegal to force newman().
557 if (!polyok(&mons
[mntmp
]) || (!forcecontrol
&& !rn2(5))
558 || your_race(&mons
[mntmp
])) {
561 (void) polymon(mntmp
);
563 sex_change_ok
--; /* reset */
566 new_light
= emits_light(youmonst
.data
);
567 if (old_light
!= new_light
) {
569 del_light_source(LS_MONSTER
, monst_to_any(&youmonst
));
571 ++new_light
; /* otherwise it's undetectable */
573 new_light_source(u
.ux
, u
.uy
, new_light
, LS_MONSTER
,
574 monst_to_any(&youmonst
));
578 /* (try to) make a mntmp monster out of the player;
579 returns 1 if polymorph successful */
584 boolean sticky
= sticks(youmonst
.data
) && u
.ustuck
&& !u
.uswallow
,
585 was_blind
= !!Blind
, dochange
= FALSE
;
588 if (mvitals
[mntmp
].mvflags
& G_GENOD
) { /* allow G_EXTINCT */
589 You_feel("rather %s-ish.", mons
[mntmp
].mname
);
590 exercise(A_WIS
, TRUE
);
595 u
.uconduct
.polyselfs
++;
597 /* exercise used to be at the very end but only Wis was affected
598 there since the polymorph was always in effect by then */
599 exercise(A_CON
, FALSE
);
600 exercise(A_WIS
, TRUE
);
603 /* Human to monster; save human stats */
606 u
.mfemale
= flags
.female
;
608 /* Monster to monster; restore human stats, to be
609 * immediately changed to provide stats for the new monster
613 flags
.female
= u
.mfemale
;
616 /* if stuck mimicking gold, stop immediately */
617 if (multi
< 0 && youmonst
.m_ap_type
== M_AP_OBJECT
618 && youmonst
.data
->mlet
!= S_MIMIC
)
620 /* if becoming a non-mimic, stop mimicking anything */
621 if (mons
[mntmp
].mlet
!= S_MIMIC
) {
622 /* as in polyman() */
623 youmonst
.m_ap_type
= M_AP_NOTHING
;
625 if (is_male(&mons
[mntmp
])) {
628 } else if (is_female(&mons
[mntmp
])) {
631 } else if (!is_neuter(&mons
[mntmp
]) && mntmp
!= u
.ulycn
) {
632 if (sex_change_ok
&& !rn2(10))
636 flags
.female
= !flags
.female
;
638 (u
.umonnum
!= mntmp
) ? "turn into a" : "feel like a new",
639 (is_male(&mons
[mntmp
]) || is_female(&mons
[mntmp
]))
641 : flags
.female
? "female " : "male ",
644 if (u
.umonnum
!= mntmp
)
645 You("turn into %s!", an(mons
[mntmp
].mname
));
647 You_feel("like a new %s!", mons
[mntmp
].mname
);
649 if (Stoned
&& poly_when_stoned(&mons
[mntmp
])) {
650 /* poly_when_stoned already checked stone golem genocide */
651 mntmp
= PM_STONE_GOLEM
;
652 make_stoned(0L, "You turn to stone!", 0, (char *) 0);
655 u
.mtimedone
= rn1(500, 500);
659 /* New stats for monster, to last only as long as polymorphed.
660 * Currently only strength gets changed.
662 if (strongmonst(&mons
[mntmp
]))
663 ABASE(A_STR
) = AMAX(A_STR
) = STR18(100);
665 if (Stone_resistance
&& Stoned
) { /* parnes@eniac.seas.upenn.edu */
666 make_stoned(0L, "You no longer seem to be petrifying.", 0,
669 if (Sick_resistance
&& Sick
) {
670 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
671 You("no longer feel sick.");
674 if (flaming(youmonst
.data
)) {
675 make_slimed(0L, "The slime burns away!");
676 } else if (mntmp
== PM_GREEN_SLIME
) {
678 make_slimed(0L, (char *) 0);
681 check_strangling(FALSE
); /* maybe stop strangling */
682 if (nohands(youmonst
.data
))
686 mlvl = adj_lev(&mons[mntmp]);
687 * We can't do the above, since there's no such thing as an
688 * "experience level of you as a monster" for a polymorphed character.
690 mlvl
= (int) mons
[mntmp
].mlevel
;
691 if (youmonst
.data
->mlet
== S_DRAGON
&& mntmp
>= PM_GRAY_DRAGON
) {
692 u
.mhmax
= In_endgame(&u
.uz
) ? (8 * mlvl
) : (4 * mlvl
+ d(mlvl
, 4));
693 } else if (is_golem(youmonst
.data
)) {
694 u
.mhmax
= golemhp(mntmp
);
699 u
.mhmax
= d(mlvl
, 8);
700 if (is_home_elemental(&mons
[mntmp
]))
705 if (u
.ulevel
< mlvl
) {
706 /* Low level characters can't become high level monsters for long */
708 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
709 int mtd
= u
.mtimedone
, ulv
= u
.ulevel
;
711 u
.mtimedone
= mtd
* ulv
/ mlvl
;
713 u
.mtimedone
= u
.mtimedone
* u
.ulevel
/ mlvl
;
717 if (uskin
&& mntmp
!= armor_to_dragon(uskin
->otyp
))
721 (void) hideunder(&youmonst
);
723 if (u
.utraptype
== TT_PIT
&& u
.utrap
) {
724 u
.utrap
= rn1(6, 2); /* time to escape resets */
726 if (was_blind
&& !Blind
) { /* previous form was eyeless */
728 make_blinded(0L, TRUE
); /* remove blindness */
730 newsym(u
.ux
, u
.uy
); /* Change symbol */
732 if (!sticky
&& !u
.uswallow
&& u
.ustuck
&& sticks(youmonst
.data
))
734 else if (sticky
&& !sticks(youmonst
.data
))
737 if (touch_petrifies(u
.usteed
->data
) && !Stone_resistance
&& rnl(3)) {
740 pline("%s touch %s.", no_longer_petrify_resistant
,
742 Sprintf(buf
, "riding %s", an(u
.usteed
->data
->mname
));
745 if (!can_ride(u
.usteed
))
746 dismount_steed(DISMOUNT_POLY
);
750 static const char use_thec
[] = "Use the command #%s to %s.";
751 static const char monsterc
[] = "monster";
753 if (can_breathe(youmonst
.data
))
754 pline(use_thec
, monsterc
, "use your breath weapon");
755 if (attacktype(youmonst
.data
, AT_SPIT
))
756 pline(use_thec
, monsterc
, "spit venom");
757 if (youmonst
.data
->mlet
== S_NYMPH
)
758 pline(use_thec
, monsterc
, "remove an iron ball");
759 if (attacktype(youmonst
.data
, AT_GAZE
))
760 pline(use_thec
, monsterc
, "gaze at monsters");
761 if (is_hider(youmonst
.data
))
762 pline(use_thec
, monsterc
, "hide");
763 if (is_were(youmonst
.data
))
764 pline(use_thec
, monsterc
, "summon help");
765 if (webmaker(youmonst
.data
))
766 pline(use_thec
, monsterc
, "spin a web");
767 if (u
.umonnum
== PM_GREMLIN
)
768 pline(use_thec
, monsterc
, "multiply in a fountain");
769 if (is_unicorn(youmonst
.data
))
770 pline(use_thec
, monsterc
, "use your horn");
771 if (is_mind_flayer(youmonst
.data
))
772 pline(use_thec
, monsterc
, "emit a mental blast");
773 if (youmonst
.data
->msound
== MS_SHRIEK
) /* worthless, actually */
774 pline(use_thec
, monsterc
, "shriek");
775 if (is_vampire(youmonst
.data
))
776 pline(use_thec
, monsterc
, "change shape");
778 if (lays_eggs(youmonst
.data
) && flags
.female
)
779 pline(use_thec
, "sit", "lay an egg");
782 /* you now know what an egg of your type looks like */
783 if (lays_eggs(youmonst
.data
)) {
784 learn_egg_type(u
.umonnum
);
785 /* make queen bees recognize killer bee eggs */
786 learn_egg_type(egg_type_from_parent(u
.umonnum
, TRUE
));
789 if ((!Levitation
&& !u
.ustuck
&& !Flying
&& is_pool_or_lava(u
.ux
, u
.uy
))
790 || (Underwater
&& !Swimming
))
792 if (Passes_walls
&& u
.utrap
793 && (u
.utraptype
== TT_INFLOOR
|| u
.utraptype
== TT_BURIEDBALL
)) {
795 if (u
.utraptype
== TT_INFLOOR
)
796 pline_The("rock seems to no longer trap you.");
798 pline_The("buried ball is no longer bound to you.");
799 buried_ball_to_freedom();
801 } else if (likes_lava(youmonst
.data
) && u
.utrap
802 && u
.utraptype
== TT_LAVA
) {
804 pline_The("lava now feels soothing.");
806 if (amorphous(youmonst
.data
) || is_whirly(youmonst
.data
)
807 || unsolid(youmonst
.data
)) {
809 You("slip out of the iron chain.");
811 } else if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
) {
812 You("slip free of the buried ball and chain.");
813 buried_ball_to_freedom();
816 if (u
.utrap
&& (u
.utraptype
== TT_WEB
|| u
.utraptype
== TT_BEARTRAP
)
817 && (amorphous(youmonst
.data
) || is_whirly(youmonst
.data
)
818 || unsolid(youmonst
.data
) || (youmonst
.data
->msize
<= MZ_SMALL
819 && u
.utraptype
== TT_BEARTRAP
))) {
820 You("are no longer stuck in the %s.",
821 u
.utraptype
== TT_WEB
? "web" : "bear trap");
822 /* probably should burn webs too if PM_FIRE_ELEMENTAL */
825 if (webmaker(youmonst
.data
) && u
.utrap
&& u
.utraptype
== TT_WEB
) {
826 You("orient yourself on the web.");
829 check_strangling(TRUE
); /* maybe start strangling */
830 (void) polysense(youmonst
.data
);
833 vision_full_recalc
= 1;
835 (void) encumber_msg();
837 retouch_equipment(2);
838 /* this might trigger a recursive call to polymon() [stone golem
839 wielding cockatrice corpse and hit by stone-to-flesh, becomes
840 flesh golem above, now gets transformed back into stone golem] */
842 selftouch(no_longer_petrify_resistant
);
849 register struct obj
*otmp
;
851 if (breakarm(youmonst
.data
)) {
852 if ((otmp
= uarm
) != 0) {
855 You("break out of your armor!");
856 exercise(A_STR
, FALSE
);
860 if ((otmp
= uarmc
) != 0) {
861 if (otmp
->oartifact
) {
862 Your("%s falls off!", cloak_simple_name(otmp
));
866 Your("%s tears apart!", cloak_simple_name(otmp
));
872 Your("shirt rips to shreds!");
875 } else if (sliparm(youmonst
.data
)) {
876 if (((otmp
= uarm
) != 0) && (racial_exception(&youmonst
, otmp
) < 1)) {
879 Your("armor falls around you!");
883 if ((otmp
= uarmc
) != 0) {
884 if (is_whirly(youmonst
.data
))
885 Your("%s falls, unsupported!", cloak_simple_name(otmp
));
887 You("shrink out of your %s!", cloak_simple_name(otmp
));
891 if ((otmp
= uarmu
) != 0) {
892 if (is_whirly(youmonst
.data
))
893 You("seep right through your shirt!");
895 You("become much too small for your shirt!");
896 setworn((struct obj
*) 0, otmp
->owornmask
& W_ARMU
);
900 if (has_horns(youmonst
.data
)) {
901 if ((otmp
= uarmh
) != 0) {
902 if (is_flimsy(otmp
) && !donning(otmp
)) {
905 /* Future possibilities: This could damage/destroy helmet */
906 Sprintf(hornbuf
, "horn%s", plur(num_horns(youmonst
.data
)));
907 Your("%s %s through %s.", hornbuf
, vtense(hornbuf
, "pierce"),
912 Your("%s falls to the %s!", helm_simple_name(otmp
),
913 surface(u
.ux
, u
.uy
));
919 if (nohands(youmonst
.data
) || verysmall(youmonst
.data
)) {
920 if ((otmp
= uarmg
) != 0) {
923 /* Drop weapon along with gloves */
924 You("drop your gloves%s!", uwep
? " and weapon" : "");
929 if ((otmp
= uarms
) != 0) {
930 You("can no longer hold your shield!");
934 if ((otmp
= uarmh
) != 0) {
937 Your("%s falls to the %s!", helm_simple_name(otmp
),
938 surface(u
.ux
, u
.uy
));
943 if (nohands(youmonst
.data
) || verysmall(youmonst
.data
)
944 || slithy(youmonst
.data
) || youmonst
.data
->mlet
== S_CENTAUR
) {
945 if ((otmp
= uarmf
) != 0) {
948 if (is_whirly(youmonst
.data
))
949 Your("boots fall away!");
951 Your("boots %s off your feet!",
952 verysmall(youmonst
.data
) ? "slide" : "are pushed");
964 const char *what
, *which
, *whichtoo
;
965 boolean candropwep
, candropswapwep
;
968 /* !alone check below is currently superfluous but in the
969 * future it might not be so if there are monsters which cannot
970 * wear gloves but can wield weapons
972 if (!alone
|| cantwield(youmonst
.data
)) {
973 candropwep
= canletgo(uwep
, "");
974 candropswapwep
= !u
.twoweap
|| canletgo(uswapwep
, "");
976 what
= (candropwep
&& candropswapwep
) ? "drop" : "release";
977 which
= is_sword(uwep
) ? "sword" : weapon_descr(uwep
);
980 is_sword(uswapwep
) ? "sword" : weapon_descr(uswapwep
);
981 if (strcmp(which
, whichtoo
))
984 if (uwep
->quan
!= 1L || u
.twoweap
)
985 which
= makeplural(which
);
987 You("find you must %s %s %s!", what
,
988 the_your
[!!strncmp(which
, "corpse", 6)], which
);
1001 } else if (!could_twoweap(youmonst
.data
)) {
1010 /* You can't revert back while unchanging */
1011 if (Unchanging
&& (u
.mh
< 1)) {
1012 killer
.format
= NO_KILLER_PREFIX
;
1013 Strcpy(killer
.name
, "killed while stuck in creature form");
1017 if (emits_light(youmonst
.data
))
1018 del_light_source(LS_MONSTER
, monst_to_any(&youmonst
));
1019 polyman("return to %s form!", urace
.adj
);
1022 /* can only happen if some bit of code reduces u.uhp
1023 instead of u.mh while poly'd */
1024 Your("old form was not healthy enough to survive.");
1025 Sprintf(killer
.name
, "reverting to unhealthy %s form", urace
.adj
);
1026 killer
.format
= KILLED_BY
;
1032 vision_full_recalc
= 1;
1033 (void) encumber_msg();
1035 retouch_equipment(2);
1037 selftouch(no_longer_petrify_resistant
);
1043 struct attack
*mattk
;
1046 You_cant("breathe. Sorry.");
1050 You("don't have enough energy to breathe!");
1056 if (!getdir((char *) 0))
1059 mattk
= attacktype_fordmg(youmonst
.data
, AT_BREA
, AD_ANY
);
1061 impossible("bad breath attack?"); /* mouthwash needed... */
1062 else if (!u
.dx
&& !u
.dy
&& !u
.dz
)
1065 buzz((int) (20 + mattk
->adtyp
- 1), (int) mattk
->damn
, u
.ux
, u
.uy
,
1074 struct attack
*mattk
;
1076 if (!getdir((char *) 0))
1078 mattk
= attacktype_fordmg(youmonst
.data
, AT_SPIT
, AD_ANY
);
1080 impossible("bad spit attack?");
1082 switch (mattk
->adtyp
) {
1085 otmp
= mksobj(BLINDING_VENOM
, TRUE
, FALSE
);
1088 impossible("bad attack type in dospit");
1091 otmp
= mksobj(ACID_VENOM
, TRUE
, FALSE
);
1094 otmp
->spe
= 1; /* to indicate it's yours */
1095 throwit(otmp
, 0L, FALSE
);
1104 if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
) {
1105 pline_The("ball and chain are buried firmly in the %s.",
1106 surface(u
.ux
, u
.uy
));
1109 You("are not chained to anything!");
1119 register struct trap
*ttmp
= t_at(u
.ux
, u
.uy
);
1121 if (Levitation
|| Is_airlevel(&u
.uz
) || Underwater
1122 || Is_waterlevel(&u
.uz
)) {
1123 You("must be on the ground to spin a web.");
1127 You("release web fluid inside %s.", mon_nam(u
.ustuck
));
1128 if (is_animal(u
.ustuck
->data
)) {
1129 expels(u
.ustuck
, u
.ustuck
->data
, TRUE
);
1132 if (is_whirly(u
.ustuck
->data
)) {
1135 for (i
= 0; i
< NATTK
; i
++)
1136 if (u
.ustuck
->data
->mattk
[i
].aatyp
== AT_ENGL
)
1139 impossible("Swallower has no engulfing attack?");
1144 switch (u
.ustuck
->data
->mattk
[i
].adtyp
) {
1146 Strcpy(sweep
, "ignites and ");
1149 Strcpy(sweep
, "fries and ");
1152 Strcpy(sweep
, "freezes, shatters and ");
1155 pline_The("web %sis swept away!", sweep
);
1158 } /* default: a nasty jelly-like creature */
1159 pline_The("web dissolves into %s.", mon_nam(u
.ustuck
));
1163 You("cannot spin webs while stuck in a trap.");
1166 exercise(A_DEX
, TRUE
);
1168 switch (ttmp
->ttyp
) {
1171 You("spin a web, covering up the pit.");
1173 bury_objs(u
.ux
, u
.uy
);
1177 pline_The("squeaky board is muffled.");
1184 case VIBRATING_SQUARE
:
1185 Your("webbing vanishes!");
1188 You("make the web thicker.");
1192 You("web over the %s.",
1193 (ttmp
->ttyp
== TRAPDOOR
) ? "trap door" : "hole");
1197 case ROLLING_BOULDER_TRAP
:
1198 You("spin a web, jamming the trigger.");
1213 You("have triggered a trap!");
1217 impossible("Webbing over trap type %d?", ttmp
->ttyp
);
1220 } else if (On_stairs(u
.ux
, u
.uy
)) {
1221 /* cop out: don't let them hide the stairs */
1222 Your("web fails to impede access to the %s.",
1223 (levl
[u
.ux
][u
.uy
].typ
== STAIRS
) ? "stairs" : "ladder");
1226 ttmp
= maketrap(u
.ux
, u
.uy
, WEB
);
1239 You("lack the energy to send forth a call for help!");
1245 You("call upon your brethren for help!");
1246 exercise(A_WIS
, TRUE
);
1247 if (!were_summon(youmonst
.data
, TRUE
, &placeholder
, (char *) 0))
1248 pline("But none arrive.");
1255 register struct monst
*mtmp
;
1261 for (i
= 0; i
< NATTK
; i
++) {
1262 if (youmonst
.data
->mattk
[i
].aatyp
== AT_GAZE
) {
1263 adtyp
= youmonst
.data
->mattk
[i
].adtyp
;
1267 if (adtyp
!= AD_CONF
&& adtyp
!= AD_FIRE
) {
1268 impossible("gaze attack %d?", adtyp
);
1273 You_cant("see anything to gaze at.");
1275 } else if (Hallucination
) {
1276 You_cant("gaze at anything you can see.");
1280 You("lack the energy to use your special gaze!");
1286 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
1287 if (DEADMONSTER(mtmp
))
1289 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
)) {
1291 if (Invis
&& !perceives(mtmp
->data
)) {
1292 pline("%s seems not to notice your gaze.", Monnam(mtmp
));
1293 } else if (mtmp
->minvis
&& !See_invisible
) {
1294 You_cant("see where to gaze at %s.", Monnam(mtmp
));
1295 } else if (mtmp
->m_ap_type
== M_AP_FURNITURE
1296 || mtmp
->m_ap_type
== M_AP_OBJECT
) {
1299 } else if (flags
.safe_dog
&& mtmp
->mtame
&& !Confusion
) {
1300 You("avoid gazing at %s.", y_monnam(mtmp
));
1302 if (flags
.confirm
&& mtmp
->mpeaceful
&& !Confusion
) {
1303 Sprintf(qbuf
, "Really %s %s?",
1304 (adtyp
== AD_CONF
) ? "confuse" : "attack",
1306 if (yn(qbuf
) != 'y')
1310 if (!mtmp
->mcanmove
|| mtmp
->mstun
|| mtmp
->msleeping
1311 || !mtmp
->mcansee
|| !haseyes(mtmp
->data
)) {
1315 /* No reflection check for consistency with when a monster
1316 * gazes at *you*--only medusa gaze gets reflected then.
1318 if (adtyp
== AD_CONF
) {
1320 Your("gaze confuses %s!", mon_nam(mtmp
));
1322 pline("%s is getting more and more confused.",
1325 } else if (adtyp
== AD_FIRE
) {
1326 int dmg
= d(2, 6), lev
= (int) u
.ulevel
;
1328 You("attack %s with a fiery gaze!", mon_nam(mtmp
));
1329 if (resists_fire(mtmp
)) {
1330 pline_The("fire doesn't burn %s!", mon_nam(mtmp
));
1334 (void) destroy_mitem(mtmp
, SCROLL_CLASS
, AD_FIRE
);
1336 (void) destroy_mitem(mtmp
, POTION_CLASS
, AD_FIRE
);
1338 (void) destroy_mitem(mtmp
, SPBOOK_CLASS
, AD_FIRE
);
1344 /* For consistency with passive() in uhitm.c, this only
1345 * affects you if the monster is still alive.
1347 if (DEADMONSTER(mtmp
))
1350 if (mtmp
->data
== &mons
[PM_FLOATING_EYE
] && !mtmp
->mcan
) {
1352 You("are frozen by %s gaze!",
1353 s_suffix(mon_nam(mtmp
)));
1354 nomul((u
.ulevel
> 6 || rn2(4))
1355 ? -d((int) mtmp
->m_lev
+ 1,
1356 (int) mtmp
->data
->mattk
[0].damd
)
1358 multi_reason
= "frozen by a monster's gaze";
1362 You("stiffen momentarily under %s gaze.",
1363 s_suffix(mon_nam(mtmp
)));
1365 /* Technically this one shouldn't affect you at all because
1366 * the Medusa gaze is an active monster attack that only
1367 * works on the monster's turn, but for it to *not* have an
1368 * effect would be too weird.
1370 if (mtmp
->data
== &mons
[PM_MEDUSA
] && !mtmp
->mcan
) {
1371 pline("Gazing at the awake %s is not a very good idea.",
1373 /* as if gazing at a sleeping anything is fruitful... */
1374 You("turn to stone...");
1375 killer
.format
= KILLED_BY
;
1376 Strcpy(killer
.name
, "deliberately meeting Medusa's gaze");
1383 You("gaze at no place in particular.");
1390 boolean ismimic
= youmonst
.data
->mlet
== S_MIMIC
,
1391 on_ceiling
= is_clinger(youmonst
.data
) || Flying
;
1393 /* can't hide while being held (or holding) or while trapped
1394 (except for floor hiders [trapper or mimic] in pits) */
1395 if (u
.ustuck
|| (u
.utrap
&& (u
.utraptype
!= TT_PIT
|| on_ceiling
))) {
1396 You_cant("hide while you're %s.",
1397 !u
.ustuck
? "trapped" : !sticks(youmonst
.data
)
1399 : humanoid(u
.ustuck
->data
)
1401 : "holding that creature");
1403 || (ismimic
&& youmonst
.m_ap_type
!= M_AP_NOTHING
)) {
1405 youmonst
.m_ap_type
= M_AP_NOTHING
;
1410 /* note: the eel and hides_under cases are hypothetical;
1411 such critters aren't offered the option of hiding via #monster */
1412 if (youmonst
.data
->mlet
== S_EEL
&& !is_pool(u
.ux
, u
.uy
)) {
1413 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
))
1414 The("fountain is not deep enough to hide in.");
1416 There("is no water to hide in here.");
1420 if (hides_under(youmonst
.data
) && !level
.objects
[u
.ux
][u
.uy
]) {
1421 There("is nothing to hide under here.");
1425 /* Planes of Air and Water */
1426 if (on_ceiling
&& !has_ceiling(&u
.uz
)) {
1427 There("is nowhere to hide above you.");
1431 if ((is_hider(youmonst
.data
) && !Flying
) /* floor hider */
1432 && (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
))) {
1433 There("is nowhere to hide beneath you.");
1437 /* TODO? inhibit floor hiding at furniture locations, or
1438 * else make youhiding() give smarter messages at such spots.
1441 if (u
.uundetected
|| (ismimic
&& youmonst
.m_ap_type
!= M_AP_NOTHING
)) {
1442 youhiding(FALSE
, 1); /* "you are already hiding" */
1447 /* should bring up a dialog "what would you like to imitate?" */
1448 youmonst
.m_ap_type
= M_AP_OBJECT
;
1449 youmonst
.mappearance
= STRANGE_OBJECT
;
1453 youhiding(FALSE
, 0); /* "you are now hiding" */
1460 struct permonst
*savedat
= youmonst
.data
;
1462 if (is_vampire(youmonst
.data
)) {
1464 if (savedat
!= youmonst
.data
) {
1465 You("transform into %s.", an(youmonst
.data
->mname
));
1475 struct monst
*mtmp
, *nmon
;
1478 You("concentrate but lack the energy to maintain doing so.");
1484 You("concentrate.");
1485 pline("A wave of psychic energy pours out.");
1486 for (mtmp
= fmon
; mtmp
; mtmp
= nmon
) {
1490 if (DEADMONSTER(mtmp
))
1492 if (distu(mtmp
->mx
, mtmp
->my
) > BOLT_LIM
* BOLT_LIM
)
1494 if (mtmp
->mpeaceful
)
1496 u_sen
= telepathic(mtmp
->data
) && !mtmp
->mcansee
;
1497 if (u_sen
|| (telepathic(mtmp
->data
) && rn2(2)) || !rn2(10)) {
1498 You("lock in on %s %s.", s_suffix(mon_nam(mtmp
)),
1500 : telepathic(mtmp
->data
) ? "latent telepathy" : "mind");
1501 mtmp
->mhp
-= rnd(15);
1512 pline("%s is no longer in your clutches.", Monnam(u
.ustuck
));
1522 Your("skin returns to its original form.");
1524 uskin
= (struct obj
*) 0;
1525 /* undo save/restore hack */
1526 uarm
->owornmask
&= ~I_SPECIAL
;
1531 mbodypart(mon
, part
)
1535 static NEARDATA
const char
1536 *humanoid_parts
[] = { "arm", "eye", "face", "finger",
1537 "fingertip", "foot", "hand", "handed",
1538 "head", "leg", "light headed", "neck",
1539 "spine", "toe", "hair", "blood",
1540 "lung", "nose", "stomach" },
1541 *jelly_parts
[] = { "pseudopod", "dark spot", "front",
1542 "pseudopod extension", "pseudopod extremity",
1543 "pseudopod root", "grasp", "grasped",
1544 "cerebral area", "lower pseudopod", "viscous",
1545 "middle", "surface", "pseudopod extremity",
1546 "ripples", "juices", "surface", "sensor",
1548 *animal_parts
[] = { "forelimb", "eye", "face",
1549 "foreclaw", "claw tip", "rear claw",
1550 "foreclaw", "clawed", "head",
1551 "rear limb", "light headed", "neck",
1552 "spine", "rear claw tip", "fur",
1553 "blood", "lung", "nose",
1555 *bird_parts
[] = { "wing", "eye", "face", "wing",
1556 "wing tip", "foot", "wing", "winged",
1557 "head", "leg", "light headed", "neck",
1558 "spine", "toe", "feathers", "blood",
1559 "lung", "bill", "stomach" },
1560 *horse_parts
[] = { "foreleg", "eye", "face",
1561 "forehoof", "hoof tip", "rear hoof",
1562 "forehoof", "hooved", "head",
1563 "rear leg", "light headed", "neck",
1564 "backbone", "rear hoof tip", "mane",
1565 "blood", "lung", "nose",
1567 *sphere_parts
[] = { "appendage", "optic nerve", "body", "tentacle",
1568 "tentacle tip", "lower appendage", "tentacle",
1569 "tentacled", "body", "lower tentacle",
1570 "rotational", "equator", "body",
1571 "lower tentacle tip", "cilia", "life force",
1572 "retina", "olfactory nerve", "interior" },
1573 *fungus_parts
[] = { "mycelium", "visual area", "front",
1574 "hypha", "hypha", "root",
1575 "strand", "stranded", "cap area",
1576 "rhizome", "sporulated", "stalk",
1577 "root", "rhizome tip", "spores",
1578 "juices", "gill", "gill",
1580 *vortex_parts
[] = { "region", "eye", "front",
1581 "minor current", "minor current", "lower current",
1582 "swirl", "swirled", "central core",
1583 "lower current", "addled", "center",
1584 "currents", "edge", "currents",
1585 "life force", "center", "leading edge",
1587 *snake_parts
[] = { "vestigial limb", "eye", "face", "large scale",
1588 "large scale tip", "rear region", "scale gap",
1589 "scale gapped", "head", "rear region",
1590 "light headed", "neck", "length", "rear scale",
1591 "scales", "blood", "lung", "forked tongue",
1593 *worm_parts
[] = { "anterior segment", "light sensitive cell",
1594 "clitellum", "setae", "setae", "posterior segment",
1595 "segment", "segmented", "anterior segment",
1596 "posterior", "over stretched", "clitellum",
1597 "length", "posterior setae", "setae", "blood",
1598 "skin", "prostomium", "stomach" },
1599 *fish_parts
[] = { "fin", "eye", "premaxillary", "pelvic axillary",
1600 "pelvic fin", "anal fin", "pectoral fin", "finned",
1601 "head", "peduncle", "played out", "gills",
1602 "dorsal fin", "caudal fin", "scales", "blood",
1603 "gill", "nostril", "stomach" };
1604 /* claw attacks are overloaded in mons[]; most humanoids with
1605 such attacks should still reference hands rather than claws */
1606 static const char not_claws
[] = {
1607 S_HUMAN
, S_MUMMY
, S_ZOMBIE
, S_ANGEL
, S_NYMPH
, S_LEPRECHAUN
,
1608 S_QUANTMECH
, S_VAMPIRE
, S_ORC
, S_GIANT
, /* quest nemeses */
1609 '\0' /* string terminator; assert( S_xxx != 0 ); */
1611 struct permonst
*mptr
= mon
->data
;
1613 /* some special cases */
1614 if (mptr
->mlet
== S_DOG
|| mptr
->mlet
== S_FELINE
1615 || mptr
->mlet
== S_RODENT
|| mptr
== &mons
[PM_OWLBEAR
]) {
1625 return horse_parts
[part
]; /* "foreleg", "rear leg" */
1627 break; /* for other parts, use animal_parts[] below */
1629 } else if (mptr
->mlet
== S_YETI
) { /* excl. owlbear due to 'if' above */
1630 /* opposable thumbs, hence "hands", "arms", "legs", &c */
1631 return humanoid_parts
[part
]; /* yeti/sasquatch, monkey/ape */
1633 if ((part
== HAND
|| part
== HANDED
)
1634 && (humanoid(mptr
) && attacktype(mptr
, AT_CLAW
)
1635 && !index(not_claws
, mptr
->mlet
) && mptr
!= &mons
[PM_STONE_GOLEM
]
1636 && mptr
!= &mons
[PM_INCUBUS
] && mptr
!= &mons
[PM_SUCCUBUS
]))
1637 return (part
== HAND
) ? "claw" : "clawed";
1638 if ((mptr
== &mons
[PM_MUMAK
] || mptr
== &mons
[PM_MASTODON
])
1641 if (mptr
== &mons
[PM_SHARK
] && part
== HAIR
)
1642 return "skin"; /* sharks don't have scales */
1643 if ((mptr
== &mons
[PM_JELLYFISH
] || mptr
== &mons
[PM_KRAKEN
])
1644 && (part
== ARM
|| part
== FINGER
|| part
== HAND
|| part
== FOOT
1647 if (mptr
== &mons
[PM_FLOATING_EYE
] && part
== EYE
)
1649 if (humanoid(mptr
) && (part
== ARM
|| part
== FINGER
|| part
== FINGERTIP
1650 || part
== HAND
|| part
== HANDED
))
1651 return humanoid_parts
[part
];
1652 if (mptr
== &mons
[PM_RAVEN
])
1653 return bird_parts
[part
];
1654 if (mptr
->mlet
== S_CENTAUR
|| mptr
->mlet
== S_UNICORN
1655 || (mptr
== &mons
[PM_ROTHE
] && part
!= HAIR
))
1656 return horse_parts
[part
];
1657 if (mptr
->mlet
== S_LIGHT
) {
1660 else if (part
== ARM
|| part
== FINGER
|| part
== FINGERTIP
1666 if (mptr
== &mons
[PM_STALKER
] && part
== HEAD
)
1668 if (mptr
->mlet
== S_EEL
&& mptr
!= &mons
[PM_JELLYFISH
])
1669 return fish_parts
[part
];
1670 if (mptr
->mlet
== S_WORM
)
1671 return worm_parts
[part
];
1672 if (slithy(mptr
) || (mptr
->mlet
== S_DRAGON
&& part
== HAIR
))
1673 return snake_parts
[part
];
1674 if (mptr
->mlet
== S_EYE
)
1675 return sphere_parts
[part
];
1676 if (mptr
->mlet
== S_JELLY
|| mptr
->mlet
== S_PUDDING
1677 || mptr
->mlet
== S_BLOB
|| mptr
== &mons
[PM_JELLYFISH
])
1678 return jelly_parts
[part
];
1679 if (mptr
->mlet
== S_VORTEX
|| mptr
->mlet
== S_ELEMENTAL
)
1680 return vortex_parts
[part
];
1681 if (mptr
->mlet
== S_FUNGUS
)
1682 return fungus_parts
[part
];
1684 return humanoid_parts
[part
];
1685 return animal_parts
[part
];
1692 return mbodypart(&youmonst
, part
);
1698 /* Returns gender of polymorphed player;
1699 * 0/1=same meaning as flags.female, 2=none.
1701 if (is_neuter(youmonst
.data
) || !humanoid(youmonst
.data
))
1703 return flags
.female
;
1707 ugolemeffects(damtype
, dam
)
1712 /* We won't bother with "slow"/"haste" since players do not
1713 * have a monster-specific slow/haste so there is no way to
1714 * restore the old velocity once they are back to human.
1716 if (u
.umonnum
!= PM_FLESH_GOLEM
&& u
.umonnum
!= PM_IRON_GOLEM
)
1720 if (u
.umonnum
== PM_FLESH_GOLEM
)
1721 heal
= (dam
+ 5) / 6; /* Approx 1 per die */
1724 if (u
.umonnum
== PM_IRON_GOLEM
)
1728 if (heal
&& (u
.mh
< u
.mhmax
)) {
1733 pline("Strangely, you feel better than before.");
1734 exercise(A_STR
, TRUE
);
1739 armor_to_dragon(atyp
)
1743 case GRAY_DRAGON_SCALE_MAIL
:
1744 case GRAY_DRAGON_SCALES
:
1745 return PM_GRAY_DRAGON
;
1746 case SILVER_DRAGON_SCALE_MAIL
:
1747 case SILVER_DRAGON_SCALES
:
1748 return PM_SILVER_DRAGON
;
1749 #if 0 /* DEFERRED */
1750 case SHIMMERING_DRAGON_SCALE_MAIL
:
1751 case SHIMMERING_DRAGON_SCALES
:
1752 return PM_SHIMMERING_DRAGON
;
1754 case RED_DRAGON_SCALE_MAIL
:
1755 case RED_DRAGON_SCALES
:
1756 return PM_RED_DRAGON
;
1757 case ORANGE_DRAGON_SCALE_MAIL
:
1758 case ORANGE_DRAGON_SCALES
:
1759 return PM_ORANGE_DRAGON
;
1760 case WHITE_DRAGON_SCALE_MAIL
:
1761 case WHITE_DRAGON_SCALES
:
1762 return PM_WHITE_DRAGON
;
1763 case BLACK_DRAGON_SCALE_MAIL
:
1764 case BLACK_DRAGON_SCALES
:
1765 return PM_BLACK_DRAGON
;
1766 case BLUE_DRAGON_SCALE_MAIL
:
1767 case BLUE_DRAGON_SCALES
:
1768 return PM_BLUE_DRAGON
;
1769 case GREEN_DRAGON_SCALE_MAIL
:
1770 case GREEN_DRAGON_SCALES
:
1771 return PM_GREEN_DRAGON
;
1772 case YELLOW_DRAGON_SCALE_MAIL
:
1773 case YELLOW_DRAGON_SCALES
:
1774 return PM_YELLOW_DRAGON
;
1781 * Some species have awareness of other species
1785 struct permonst
*mptr
;
1789 context
.warntype
.speciesidx
= 0;
1790 context
.warntype
.species
= 0;
1791 context
.warntype
.polyd
= 0;
1793 switch (monsndx(mptr
)) {
1794 case PM_PURPLE_WORM
:
1795 warnidx
= PM_SHRIEKER
;
1798 case PM_VAMPIRE_LORD
:
1799 context
.warntype
.polyd
= M2_HUMAN
| M2_ELF
;
1800 HWarn_of_mon
|= FROMRACE
;
1804 context
.warntype
.speciesidx
= warnidx
;
1805 context
.warntype
.species
= &mons
[warnidx
];
1806 HWarn_of_mon
|= FROMRACE
;
1809 context
.warntype
.speciesidx
= 0;
1810 context
.warntype
.species
= 0;
1811 HWarn_of_mon
&= ~FROMRACE
;