1 /* NetHack 3.7 polyself.c $NHDT-Date: 1703845752 2023/12/29 10:29:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.207 $ */
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 gy.youmonst.m_id
9 * always remains 1 and gy.youmonst.mx will always remain 0 when it handles
10 * the case of the 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 staticfn
void check_strangling(boolean
);
25 staticfn
void polyman(const char *, const char *);
26 staticfn
void dropp(struct obj
*);
27 staticfn
void break_armor(void);
28 staticfn
void drop_weapon(int);
29 staticfn
int armor_to_dragon(int);
30 staticfn
void newman(void);
31 staticfn
void polysense(void);
33 static const char no_longer_petrify_resistant
[] =
34 "No longer petrify-resistant, you";
36 /* update the gy.youmonst.data structure pointer and intrinsics */
40 struct permonst
*mdat
= &mons
[u
.umonnum
];
41 boolean was_vampshifter
= valid_vampshiftform(gy
.youmonst
.cham
, u
.umonnum
);
43 set_mon_data(&gy
.youmonst
, mdat
);
46 if (Protection_from_shape_changers
)
47 gy
.youmonst
.cham
= NON_PM
;
48 else if (is_vampire(gy
.youmonst
.data
))
49 gy
.youmonst
.cham
= gy
.youmonst
.mnum
;
50 /* assume hero-as-chameleon/doppelganger/sandestin doesn't change shape */
51 else if (!was_vampshifter
)
52 gy
.youmonst
.cham
= NON_PM
;
53 u
.mcham
= gy
.youmonst
.cham
; /* for save/restore since youmonst isn't */
55 #define PROPSET(PropIndx, ON) \
58 u.uprops[PropIndx].intrinsic |= FROMFORM; \
60 u.uprops[PropIndx].intrinsic &= ~FROMFORM; \
63 PROPSET(FIRE_RES
, resists_fire(&gy
.youmonst
));
64 PROPSET(COLD_RES
, resists_cold(&gy
.youmonst
));
65 PROPSET(SLEEP_RES
, resists_sleep(&gy
.youmonst
));
66 PROPSET(DISINT_RES
, resists_disint(&gy
.youmonst
));
67 PROPSET(SHOCK_RES
, resists_elec(&gy
.youmonst
));
68 PROPSET(POISON_RES
, resists_poison(&gy
.youmonst
));
69 PROPSET(ACID_RES
, resists_acid(&gy
.youmonst
));
70 PROPSET(STONE_RES
, resists_ston(&gy
.youmonst
));
72 /* resists_drli() takes wielded weapon into account; suppress it */
73 struct obj
*save_uwep
= uwep
;
76 PROPSET(DRAIN_RES
, resists_drli(&gy
.youmonst
));
79 /* resists_magm() takes wielded, worn, and carried equipment into
80 into account; cheat and duplicate its monster-specific part */
81 PROPSET(ANTIMAGIC
, (dmgtype(mdat
, AD_MAGM
)
82 || mdat
== &mons
[PM_BABY_GRAY_DRAGON
]
83 || dmgtype(mdat
, AD_RBRE
)));
84 PROPSET(SICK_RES
, (mdat
->mlet
== S_FUNGUS
|| mdat
== &mons
[PM_GHOUL
]));
86 PROPSET(STUNNED
, (mdat
== &mons
[PM_STALKER
] || is_bat(mdat
)));
87 PROPSET(HALLUC_RES
, dmgtype(mdat
, AD_HALU
));
88 PROPSET(SEE_INVIS
, perceives(mdat
));
89 PROPSET(TELEPAT
, telepathic(mdat
));
90 /* note that Infravision uses mons[race] rather than usual mons[role] */
91 PROPSET(INFRAVISION
, infravision(Upolyd
? mdat
: &mons
[gu
.urace
.mnum
]));
92 PROPSET(INVIS
, pm_invisible(mdat
));
93 PROPSET(TELEPORT
, can_teleport(mdat
));
94 PROPSET(TELEPORT_CONTROL
, control_teleport(mdat
));
95 PROPSET(LEVITATION
, is_floater(mdat
));
96 /* floating eye is the only 'floater'; it is also flagged as a 'flyer';
97 suppress flying for it so that enlightenment doesn't confusingly
98 show latent flight capability always blocked by levitation */
99 PROPSET(FLYING
, (is_flyer(mdat
) && !is_floater(mdat
)));
100 PROPSET(SWIMMING
, is_swimmer(mdat
));
101 /* [don't touch MAGICAL_BREATHING here; both Amphibious and Breathless
102 key off of it but include different monster forms...] */
103 PROPSET(PASSES_WALLS
, passes_walls(mdat
));
104 PROPSET(REGENERATION
, regenerates(mdat
));
105 PROPSET(REFLECTING
, (mdat
== &mons
[PM_SILVER_DRAGON
]));
106 PROPSET(BLINDED
, !haseyes(mdat
));
107 PROPSET(BLND_RES
, (dmgtype_fromattack(mdat
, AD_BLND
, AT_EXPL
)
108 || dmgtype_fromattack(mdat
, AD_BLND
, AT_GAZE
)));
111 /* whether the player is flying/floating depends on their steed,
112 which won't be known during the restore process: but BFlying
113 and BStealth should be set correctly already in that case, so
114 there's nothing to do */
115 if (!program_state
.restoring
)
116 float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
119 #ifdef STATUS_HILITES
120 if (VIA_WINDOWPORT())
121 status_initialize(REASSESS_ONLY
);
123 /* we can reset this now, having just done what it is meant to trigger */
124 gw
.were_changes
= 0L;
127 /* Levitation overrides Flying; set or clear BFlying|I_SPECIAL */
129 float_vs_flight(void)
131 boolean stuck_in_floor
= (u
.utrap
&& u
.utraptype
!= TT_PIT
);
133 /* floating overrides flight; so does being trapped in the floor */
134 if ((HLevitation
|| ELevitation
)
135 || ((HFlying
|| EFlying
) && stuck_in_floor
))
136 BFlying
|= I_SPECIAL
;
138 BFlying
&= ~I_SPECIAL
;
139 /* being trapped on the ground (bear trap, web, molten lava survived
140 with fire resistance, former lava solidified via cold, tethered
141 to a buried iron ball) overrides floating--the floor is reachable */
142 if ((HLevitation
|| ELevitation
) && stuck_in_floor
)
143 BLevitation
|= I_SPECIAL
;
145 BLevitation
&= ~I_SPECIAL
;
147 /* riding blocks stealth unless hero+steed fly, so a change in flying
148 might cause a change in stealth */
154 /* riding blocks stealth unless hero+steed fly */
156 steed_vs_stealth(void)
158 if (u
.usteed
&& !Flying
&& !Levitation
)
159 BStealth
|= FROMOUTSIDE
;
161 BStealth
&= ~FROMOUTSIDE
;
164 /* for changing into form that's immune to strangulation */
166 check_strangling(boolean on
)
168 /* on -- maybe resume strangling */
170 boolean was_strangled
= (Strangled
!= 0L);
172 /* when Strangled is already set, polymorphing from one
173 vulnerable form into another causes the counter to be reset */
174 if (uamul
&& uamul
->otyp
== AMULET_OF_STRANGULATION
175 && can_be_strangled(&gy
.youmonst
)) {
178 Your("%s %s your %s!", simpleonames(uamul
),
179 was_strangled
? "still constricts" : "begins constricting",
180 body_part(NECK
)); /* "throat" */
181 makeknown(AMULET_OF_STRANGULATION
);
184 /* off -- maybe block strangling */
186 if (Strangled
&& !can_be_strangled(&gy
.youmonst
)) {
189 You("are no longer being strangled.");
194 DISABLE_WARNING_FORMAT_NONLITERAL
196 /* make a (new) human out of the player */
198 polyman(const char *fmt
, const char *arg
)
200 boolean sticking
= (sticks(gy
.youmonst
.data
) && u
.ustuck
&& !u
.uswallow
),
201 was_mimicking
= (U_AP_TYPE
!= M_AP_NOTHING
);
202 boolean was_blind
= !!Blind
;
205 u
.acurr
= u
.macurr
; /* restore old attribs */
207 u
.umonnum
= u
.umonster
;
208 flags
.female
= u
.mfemale
;
223 gy
.youmonst
.m_ap_type
= M_AP_NOTHING
;
224 gy
.youmonst
.mappearance
= 0;
229 urgent_pline(fmt
, arg
);
230 /* check whether player foolishly genocided self while poly'd */
232 /* intervening activity might have clobbered genocide info */
233 struct kinfo
*kptr
= find_delayed_killer(POLYMORPH
);
235 if (kptr
!= (struct kinfo
*) 0 && kptr
->name
[0]) {
236 svk
.killer
.format
= kptr
->format
;
237 Strcpy(svk
.killer
.name
, kptr
->name
);
239 svk
.killer
.format
= KILLED_BY
;
240 Strcpy(svk
.killer
.name
, "self-genocide");
242 dealloc_killer(kptr
);
246 if (u
.twoweap
&& !could_twoweap(gy
.youmonst
.data
))
249 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
250 set_utrap(rn1(6, 2), TT_PIT
); /* time to escape resets */
252 if (was_blind
&& !Blind
) { /* reverting from eyeless */
253 set_itimeout(&HBlinded
, 1L);
254 make_blinded(0L, TRUE
); /* remove blindness */
256 check_strangling(TRUE
);
258 if (!Levitation
&& !u
.ustuck
&& is_pool_or_lava(u
.ux
, u
.uy
))
264 RESTORE_WARNING_FORMAT_NONLITERAL
269 /* Some monsters are always of one sex and their sex can't be changed;
270 * Succubi/incubi can change, but are handled below.
272 * !Upolyd check necessary because is_male() and is_female()
273 * may be true for certain roles
276 || (!is_male(gy
.youmonst
.data
) && !is_female(gy
.youmonst
.data
)
277 && !is_neuter(gy
.youmonst
.data
)))
278 flags
.female
= !flags
.female
;
279 if (Upolyd
) /* poly'd: also change saved sex */
280 u
.mfemale
= !u
.mfemale
;
281 max_rank_sz(); /* [this appears to be superfluous] */
282 if ((Upolyd
? u
.mfemale
: flags
.female
) && gu
.urole
.name
.f
)
283 Strcpy(svp
.pl_character
, gu
.urole
.name
.f
);
285 Strcpy(svp
.pl_character
, gu
.urole
.name
.m
);
287 u
.umonnum
= u
.umonster
;
288 } else if (u
.umonnum
== PM_AMOROUS_DEMON
) {
289 flags
.female
= !flags
.female
;
291 /* change monster type to match new sex; disabled with
293 u
.umonnum
= (u
.umonnum
== PM_SUCCUBUS
) ? PM_INCUBUS
: PM_SUCCUBUS
;
299 /* log a message if non-poly'd hero's gender has changed */
301 livelog_newform(boolean viapoly
, int oldgend
, int newgend
)
304 const char *oldrole
, *oldrank
, *newrole
, *newrank
;
308 * Give other logging feedback here instead of in newman().
312 if (newgend
!= oldgend
) {
313 oldrole
= (oldgend
&& gu
.urole
.name
.f
) ? gu
.urole
.name
.f
315 newrole
= (newgend
&& gu
.urole
.name
.f
) ? gu
.urole
.name
.f
317 oldrank
= rank_of(u
.ulevel
, Role_switch
, oldgend
);
318 newrank
= rank_of(u
.ulevel
, Role_switch
, newgend
);
319 Sprintf(buf
, "%.10s %.30s", genders
[flags
.female
].adj
, newrank
);
320 livelog_printf(LL_MINORAC
, "%s into %s",
321 viapoly
? "polymorphed" : "transformed",
322 an(strcmp(newrole
, oldrole
) ? newrole
323 : strcmp(newrank
, oldrank
) ? newrank
333 int i
, oldlvl
, newlvl
, oldgend
, newgend
, hpmax
, enmax
;
336 newlvl
= oldlvl
+ rn1(5, -2); /* new = old + {-2,-1,0,+1,+2} */
337 if (newlvl
> 127 || newlvl
< 1) { /* level went below 0? */
338 goto dead
; /* old level is still intact (in case of lifesaving) */
340 if (newlvl
> MAXULEV
)
342 /* If your level goes down, your peak level goes down by
343 the same amount so that you can't simply use blessed
344 full healing to undo the decrease. But if your level
345 goes up, your peak level does *not* undergo the same
346 adjustment; you might end up losing out on the chance
347 to regain some levels previously lost to other causes. */
349 u
.ulevelmax
-= (oldlvl
- newlvl
);
350 if (u
.ulevelmax
< newlvl
)
351 u
.ulevelmax
= newlvl
;
354 oldgend
= poly_gender();
355 if (gs
.sex_change_ok
&& !rn2(10))
358 adjabil(oldlvl
, (int) u
.ulevel
);
360 /* random experience points for the new experience level */
361 u
.uexp
= rndexp(FALSE
);
363 /* set up new attribute points (particularly Con) */
368 * remove "level gain"-based HP from any extra HP accumulated
369 * (the "extra" might actually be negative);
370 * modify the extra, retaining {80%, 90%, 100%, or 110%};
371 * add in newly generated set of level-gain HP.
373 * (This used to calculate new HP in direct proportion to old HP,
374 * but that was subject to abuse: accumulate a large amount of
375 * extra HP, drain level down to 1, then polyself to level 2 or 3
376 * [lifesaving capability needed to handle level 0 and -1 cases]
377 * and the extra got multiplied by 2 or 3. Repeat the level
378 * drain and polyself steps until out of lifesaving capability.)
381 for (i
= 0; i
< oldlvl
; i
++)
382 hpmax
-= (int) u
.uhpinc
[i
];
383 /* hpmax * rn1(4,8) / 10; 0.95*hpmax on average */
384 hpmax
= rounddiv((long) hpmax
* (long) rn1(4, 8), 10);
385 for (i
= 0; (u
.ulevel
= i
) < newlvl
; i
++)
387 if (hpmax
< u
.ulevel
)
388 hpmax
= u
.ulevel
; /* min of 1 HP per level */
389 /* retain same proportion for current HP; u.uhp * hpmax / u.uhpmax */
390 u
.uhp
= rounddiv((long) u
.uhp
* (long) hpmax
, u
.uhpmax
);
391 setuhpmax(hpmax
, TRUE
); /* might reduce u.uhp */
393 * Do the same for spell power.
396 for (i
= 0; i
< oldlvl
; i
++)
397 enmax
-= (int) u
.ueninc
[i
];
398 enmax
= rounddiv((long) enmax
* (long) rn1(4, 8), 10);
399 for (i
= 0; (u
.ulevel
= i
) < newlvl
; i
++)
401 if (enmax
< u
.ulevel
)
403 u
.uen
= rounddiv((long) u
.uen
* (long) enmax
,
404 ((u
.uenmax
< 1) ? 1 : u
.uenmax
));
406 /* [should alignment record be tweaked too?] */
408 u
.uhunger
= rn1(500, 500);
410 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
412 make_stoned(0L, (char *) 0, 0, (char *) 0);
414 if (Polymorph_control
) { /* even when Stunned || Unaware */
418 dead
: /* we come directly here if experience level went to 0 or less */
420 "Your new form doesn't seem healthy enough to survive.");
421 svk
.killer
.format
= KILLED_BY_AN
;
422 Strcpy(svk
.killer
.name
, "unsuccessful polymorph");
424 /* must have been life-saved to get here */
426 (void) encumber_msg(); /* used to be done by redist_attr() */
427 return; /* lifesaved */
431 /* use saved gender we're about to revert to, not current */
432 newform
= ((Upolyd
? u
.mfemale
: flags
.female
) && gu
.urace
.individual
.f
)
433 ? gu
.urace
.individual
.f
434 : (gu
.urace
.individual
.m
)
435 ? gu
.urace
.individual
.m
437 polyman("You feel like a new %s!", newform
);
439 newgend
= poly_gender();
440 /* note: newman() bypasses achievements for new ranks attained and
441 doesn't log "new <form>" when that isn't accompanied by level change */
442 if (newlvl
!= oldlvl
)
443 livelog_printf(LL_MINORAC
, "became experience level %d as a new %s",
446 livelog_newform(TRUE
, oldgend
, newgend
);
449 Your("body transforms, but there is still slime on you.");
450 make_slimed(10L, (const char *) 0);
455 (void) encumber_msg();
457 retouch_equipment(2);
459 selftouch(no_longer_petrify_resistant
);
463 polyself(int psflags
)
466 int old_light
, new_light
, mntmp
, class, tryct
, gvariant
= NEUTRAL
;
467 boolean forcecontrol
= ((psflags
& POLY_CONTROLLED
) != 0),
468 low_control
= ((psflags
& POLY_LOW_CTRL
) != 0),
469 monsterpoly
= ((psflags
& POLY_MONSTER
) != 0),
470 formrevert
= ((psflags
& POLY_REVERT
) != 0),
471 draconian
= (uarm
&& Is_dragon_armor(uarm
)),
472 iswere
= (ismnum(u
.ulycn
)),
473 isvamp
= (is_vampire(gy
.youmonst
.data
)
474 || is_vampshifter(&gy
.youmonst
)),
475 controllable_poly
= Polymorph_control
&& !(Stunned
|| Unaware
);
478 You("fail to transform!");
481 /* being Stunned|Unaware doesn't negate this aspect of Poly_control */
482 if (!Polymorph_control
&& !forcecontrol
&& !draconian
&& !iswere
484 if (rn2(20) > ACURR(A_CON
)) {
485 You1(shudder_for_moment
);
486 losehp(rnd(30), "system shock", KILLED_BY_AN
);
487 exercise(A_CON
, FALSE
);
491 old_light
= emits_light(gy
.youmonst
.data
);
495 mntmp
= gy
.youmonst
.cham
;
497 controllable_poly
= FALSE
;
500 if (forcecontrol
&& low_control
501 && (draconian
|| monsterpoly
|| isvamp
|| iswere
))
502 forcecontrol
= FALSE
;
504 if (monsterpoly
&& isvamp
)
507 if (controllable_poly
|| forcecontrol
) {
513 getlin("Become what kind of monster? [type the name]", buf
);
514 (void) mungspaces(buf
);
515 if (*buf
== '\033') {
516 /* user is cancelling controlled poly */
517 if (forcecontrol
) { /* wizard mode #polyself */
521 Strcpy(buf
, "*"); /* resort to random */
523 if (!strcmp(buf
, "*") || !strcmp(buf
, "random")) {
524 /* explicitly requesting random result */
525 tryct
= 0; /* will skip thats_enough_tries */
526 continue; /* end do-while(--tryct > 0) loop */
529 mntmp
= name_to_mon(buf
, &gvariant
);
530 if (mntmp
< LOW_PM
) {
532 class = name_to_monclass(buf
, &mntmp
);
533 if (class && mntmp
== NON_PM
)
534 mntmp
= (draconian
&& class == S_DRAGON
)
535 ? armor_to_dragon(uarm
->otyp
)
536 : mkclass_poly(class);
538 /* placeholder monsters are for corpses and all flagged
539 M2_NOPOLY but they are reasonable polymorph targets;
540 pick a suitable substitute (which might be geno'd) */
541 } else if (is_placeholder(&mons
[mntmp
])
542 /* when your own race, fall to !polyok() case */
543 && !your_race(&mons
[mntmp
])
544 /* same for generic human, even if hero isn't human */
545 && mntmp
!= PM_HUMAN
) {
546 /* far less general than mkclass() */
548 mntmp
= rn2(3) ? PM_HILL_ORC
: PM_MORDOR_ORC
;
549 else if (mntmp
== PM_ELF
)
550 mntmp
= rn2(3) ? PM_GREEN_ELF
: PM_GREY_ELF
;
551 else if (mntmp
== PM_GIANT
)
552 mntmp
= rn2(3) ? PM_STONE_GIANT
: PM_HILL_GIANT
;
553 /* note: PM_DWARF and PM_GNOME are ordinary monsters and
554 no longer flagged no-poly so have no need for placeholder
555 handling; PM_HUMAN is a placeholder without a suitable
556 substitute so gets handled differently below */
559 if (mntmp
< LOW_PM
) {
561 pline("I've never heard of such monsters.");
563 You_cant("polymorph into any of those.");
564 } else if (wizard
&& Upolyd
565 && (mntmp
== u
.umonster
566 /* "priest" and "priestess" match the monster
567 rather than the role; override that unless
568 the text explicitly contains "aligned" */
569 || (u
.umonster
== PM_CLERIC
570 && mntmp
== PM_ALIGNED_CLERIC
571 && !strstri(buf
, "aligned")))) {
572 /* in wizard mode, picking own role while poly'd reverts to
573 normal without newman()'s chance of level or sex change */
575 old_light
= 0; /* rehumanize() extinguishes u-as-mon light */
577 } else if (iswere
&& (were_beastie(mntmp
) == u
.ulycn
578 || mntmp
== counter_were(u
.ulycn
)
579 || (Upolyd
&& mntmp
== PM_HUMAN
))) {
581 } else if (!polyok(&mons
[mntmp
])
582 /* Note: humans are illegal as monsters, but an
583 illegal monster forces newman(), which is what
584 we want if they specified a human.... (unless
585 they specified a unique monster) */
586 && !(mntmp
== PM_HUMAN
587 || (your_race(&mons
[mntmp
])
588 && (mons
[mntmp
].geno
& G_UNIQ
) == 0)
589 || mntmp
== gu
.urole
.mnum
)) {
592 /* mkclass_poly() can pick a !polyok()
593 candidate; if so, usually try again */
595 if (rn2(3) || --tryct
> 0)
597 /* no retries left; put one back on counter
598 so that end of loop decrement will yield
599 0 and trigger thats_enough_tries message */
602 pm_name
= pmname(&mons
[mntmp
], flags
.female
? FEMALE
: MALE
);
603 if (the_unique_pm(&mons
[mntmp
]))
604 pm_name
= the(pm_name
);
605 else if (!type_is_pname(&mons
[mntmp
]))
606 pm_name
= an(pm_name
);
607 You_cant("polymorph into %s.", pm_name
);
610 } while (--tryct
> 0);
613 pline1(thats_enough_tries
);
614 /* allow skin merging, even when polymorph is controlled */
615 if (draconian
&& (tryct
<= 0 || mntmp
== armor_to_dragon(uarm
->otyp
)))
617 if (isvamp
&& (tryct
<= 0 || mntmp
== PM_WOLF
|| mntmp
== PM_FOG_CLOUD
618 || is_bat(&mons
[mntmp
])))
620 } else if (draconian
|| iswere
|| isvamp
) {
621 /* special changes that don't require polyok() */
624 mntmp
= armor_to_dragon(uarm
->otyp
);
625 if (!(svm
.mvitals
[mntmp
].mvflags
& G_GENOD
)) {
626 unsigned was_lit
= uarm
->lamplit
;
627 int arm_light
= artifact_light(uarm
) ? arti_light_radius(uarm
)
630 /* allow G_EXTINCT */
631 if (Is_dragon_scales(uarm
)) {
632 /* dragon scales remain intact as uskin */
633 You("merge with your scaly armor.");
634 } else { /* dragon scale mail reverts to scales */
635 /* similar to noarmor(invent.c),
636 shorten to "<color> scale mail" */
637 Strcpy(buf
, simpleonames(uarm
));
638 strsubst(buf
, " dragon ", " ");
639 /* tricky phrasing; dragon scale mail is singular, dragon
640 scales are plural (note: we don't use "set of scales",
641 which usually overrides the distinction, here) */
642 Your("%s reverts to scales as you merge with them.", buf
);
643 /* uarm->spe enchantment remains unchanged;
644 re-converting scales to mail poses risk
645 of evaporation due to over enchanting */
646 uarm
->otyp
+= GRAY_DRAGON_SCALES
- GRAY_DRAGON_SCALE_MAIL
;
648 disp
.botl
= TRUE
; /* AC is changing */
651 uarm
= (struct obj
*) 0;
652 /* save/restore hack */
653 uskin
->owornmask
|= I_SPECIAL
;
655 maybe_adjust_light(uskin
, arm_light
);
660 if (Upolyd
&& were_beastie(mntmp
) != u
.ulycn
)
661 mntmp
= PM_HUMAN
; /* Illegal; force newman() */
666 if (mntmp
< LOW_PM
|| (mons
[mntmp
].geno
& G_UNIQ
)) {
667 mntmp
= (gy
.youmonst
.data
== &mons
[PM_VAMPIRE_LEADER
]
668 && !rn2(10)) ? PM_WOLF
669 : !rn2(4) ? PM_FOG_CLOUD
671 if (ismnum(gy
.youmonst
.cham
)
672 && !is_vampire(gy
.youmonst
.data
) && !rn2(2))
673 mntmp
= gy
.youmonst
.cham
;
675 if (controllable_poly
) {
676 Sprintf(buf
, "Become %s?",
677 an(pmname(&mons
[mntmp
], gvariant
)));
682 /* if polymon fails, "you feel" message has been given
683 so don't follow up with another polymon or newman;
684 sex_change_ok left disabled here */
685 if (mntmp
== PM_HUMAN
)
686 newman(); /* werecritter */
688 (void) polymon(mntmp
);
689 goto made_change
; /* maybe not, but this is right anyway */
692 if (mntmp
< LOW_PM
) {
695 /* randomly pick an "ordinary" monster */
696 mntmp
= rn1(SPECIAL_PM
- LOW_PM
, LOW_PM
);
697 if (polyok(&mons
[mntmp
]) && !is_placeholder(&mons
[mntmp
]))
699 } while (--tryct
> 0);
702 /* The below polyok() fails either if everything is genocided, or if
703 * we deliberately chose something illegal to force newman().
706 if (!polyok(&mons
[mntmp
]) || (!forcecontrol
&& !rn2(5))
707 || your_race(&mons
[mntmp
])) {
710 (void) polymon(mntmp
);
712 gs
.sex_change_ok
--; /* reset */
715 new_light
= emits_light(gy
.youmonst
.data
);
716 if (old_light
!= new_light
) {
718 del_light_source(LS_MONSTER
, monst_to_any(&gy
.youmonst
));
720 ++new_light
; /* otherwise it's undetectable */
722 new_light_source(u
.ux
, u
.uy
, new_light
, LS_MONSTER
,
723 monst_to_any(&gy
.youmonst
));
727 /* (try to) make a mntmp monster out of the player; return 1 if successful */
731 char buf
[BUFSZ
], ustuckNam
[BUFSZ
];
732 boolean sticking
= sticks(gy
.youmonst
.data
) && u
.ustuck
&& !u
.uswallow
,
733 was_blind
= !!Blind
, dochange
= FALSE
, was_expelled
= FALSE
,
734 was_hiding_under
= u
.uundetected
&& hides_under(gy
.youmonst
.data
);
737 if (svm
.mvitals
[mntmp
].mvflags
& G_GENOD
) { /* allow G_EXTINCT */
738 You_feel("rather %s-ish.",
739 pmname(&mons
[mntmp
], flags
.female
? FEMALE
: MALE
));
740 exercise(A_WIS
, TRUE
);
745 if (!u
.uconduct
.polyselfs
++)
746 livelog_printf(LL_CONDUCT
,
747 "changed form for the first time, becoming %s",
748 an(pmname(&mons
[mntmp
], flags
.female
? FEMALE
: MALE
)));
750 /* exercise used to be at the very end but only Wis was affected
751 there since the polymorph was always in effect by then */
752 exercise(A_CON
, FALSE
);
753 exercise(A_WIS
, TRUE
);
756 /* Human to monster; save human stats */
759 u
.mfemale
= flags
.female
;
761 /* Monster to monster; restore human stats, to be
762 * immediately changed to provide stats for the new monster
766 flags
.female
= u
.mfemale
;
769 /* if stuck mimicking gold, stop immediately */
770 if (gm
.multi
< 0 && U_AP_TYPE
== M_AP_OBJECT
771 && gy
.youmonst
.data
->mlet
!= S_MIMIC
)
773 /* if becoming a non-mimic, stop mimicking anything */
774 if (mons
[mntmp
].mlet
!= S_MIMIC
) {
775 /* as in polyman() */
776 gy
.youmonst
.m_ap_type
= M_AP_NOTHING
;
777 gy
.youmonst
.mappearance
= 0;
779 if (is_male(&mons
[mntmp
])) {
782 } else if (is_female(&mons
[mntmp
])) {
785 } else if (!is_neuter(&mons
[mntmp
]) && mntmp
!= u
.ulycn
) {
786 if (gs
.sex_change_ok
&& !rn2(10))
790 Strcpy(ustuckNam
, u
.ustuck
? Some_Monnam(u
.ustuck
) : "");
792 Strcpy(buf
, (u
.umonnum
!= mntmp
) ? "" : "new ");
794 flags
.female
= !flags
.female
;
795 Strcat(buf
, (is_male(&mons
[mntmp
]) || is_female(&mons
[mntmp
]))
796 ? "" : flags
.female
? "female " : "male ");
798 Strcat(buf
, pmname(&mons
[mntmp
], flags
.female
? FEMALE
: MALE
));
799 You("%s %s!", (u
.umonnum
!= mntmp
) ? "turn into" : "feel like", an(buf
));
801 if (Stoned
&& poly_when_stoned(&mons
[mntmp
])) {
802 /* poly_when_stoned already checked stone golem genocide */
803 mntmp
= PM_STONE_GOLEM
;
804 make_stoned(0L, "You turn to stone!", 0, (char *) 0);
807 u
.mtimedone
= rn1(500, 500);
811 /* New stats for monster, to last only as long as polymorphed.
812 * Currently only strength gets changed.
814 newMaxStr
= uasmon_maxStr();
815 if (strongmonst(&mons
[mntmp
])) {
816 ABASE(A_STR
) = AMAX(A_STR
) = (schar
) newMaxStr
;
818 /* not a strongmonst(); if hero has exceptional strength, remove it
819 (note: removal is temporary until returning to original form);
820 we don't attempt to enforce lower maximum for wimpy forms;
821 unlike for strongmonst, current strength does not get set to max */
822 AMAX(A_STR
) = (schar
) newMaxStr
;
823 /* make sure current is not higher than max (strip exceptional Str) */
824 if (ABASE(A_STR
) > AMAX(A_STR
))
825 ABASE(A_STR
) = AMAX(A_STR
);
828 if (Stone_resistance
&& Stoned
) { /* parnes@eniac.seas.upenn.edu */
829 make_stoned(0L, "You no longer seem to be petrifying.", 0,
832 if (Sick_resistance
&& Sick
) {
833 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
834 You("no longer feel sick.");
837 if (flaming(gy
.youmonst
.data
)) {
838 make_slimed(0L, "The slime burns away!");
839 } else if (mntmp
== PM_GREEN_SLIME
) {
841 make_slimed(0L, (char *) 0);
844 check_strangling(FALSE
); /* maybe stop strangling */
845 if (nohands(gy
.youmonst
.data
))
849 mlvl = adj_lev(&mons[mntmp]);
850 * We can't do the above, since there's no such thing as an
851 * "experience level of you as a monster" for a polymorphed character.
853 mlvl
= (int) mons
[mntmp
].mlevel
;
854 if (gy
.youmonst
.data
->mlet
== S_DRAGON
&& mntmp
>= PM_GRAY_DRAGON
) {
855 u
.mhmax
= In_endgame(&u
.uz
) ? (8 * mlvl
) : (4 * mlvl
+ d(mlvl
, 4));
856 } else if (is_golem(gy
.youmonst
.data
)) {
857 u
.mhmax
= golemhp(mntmp
);
862 u
.mhmax
= d(mlvl
, 8);
863 if (is_home_elemental(&mons
[mntmp
]))
868 if (u
.ulevel
< mlvl
) {
869 /* Low level characters can't become high level monsters for long */
871 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
872 int mtd
= u
.mtimedone
, ulv
= u
.ulevel
;
874 u
.mtimedone
= mtd
* ulv
/ mlvl
;
876 u
.mtimedone
= u
.mtimedone
* u
.ulevel
/ mlvl
;
880 if (uskin
&& mntmp
!= armor_to_dragon(uskin
->otyp
))
884 find_ac(); /* (repeated below) */
885 /* if hiding under something and can't hide anymore, unhide now;
886 but don't auto-hide when not already hiding-under */
887 if (was_hiding_under
)
888 (void) hideunder(&gy
.youmonst
);
890 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
891 set_utrap(rn1(6, 2), TT_PIT
); /* time to escape resets */
893 if (was_blind
&& !Blind
) { /* previous form was eyeless */
894 set_itimeout(&HBlinded
, 1L);
895 make_blinded(0L, TRUE
); /* remove blindness */
897 newsym(u
.ux
, u
.uy
); /* Change symbol */
899 /* you now know what an egg of your type looks like; [moved from
900 below in case expels() -> spoteffects() drops hero onto any eggs] */
901 if (lays_eggs(gy
.youmonst
.data
)) {
902 learn_egg_type(u
.umonnum
);
903 /* make queen bees recognize killer bee eggs */
904 learn_egg_type(egg_type_from_parent(u
.umonnum
, TRUE
));
910 /* if new form can't be swallowed, make engulfer expel hero */
911 if (unsolid(gy
.youmonst
.data
)
912 /* subset of engulf_target() */
913 || (usiz
= gy
.youmonst
.data
->msize
) >= MZ_HUGE
914 || (u
.ustuck
->data
->msize
< usiz
&& !is_whirly(u
.ustuck
->data
))) {
915 boolean expels_mesg
= TRUE
;
917 if (unsolid(gy
.youmonst
.data
)) {
918 if (canspotmon(u
.ustuck
)) /* [see below for explanation] */
919 Strcpy(ustuckNam
, Monnam(u
.ustuck
));
920 pline("%s can no longer contain you.", ustuckNam
);
923 expels(u
.ustuck
, u
.ustuck
->data
, expels_mesg
);
925 /* FIXME? if expels() triggered rehumanize then we should
929 /* [note: this 'sticking' handling is only sufficient for changing from
930 grabber to engulfer or vice versa because engulfing by poly'd hero
931 always ends immediately so won't be in effect during a polymorph] */
932 } else if (u
.ustuck
&& !sticking
/* && !u.uswallow */
933 /* being held; if now capable of holding, make holder
934 release so that hero doesn't automagically start holding
935 it; or, release if no longer capable of being held */
936 && (sticks(gy
.youmonst
.data
) || unsolid(gy
.youmonst
.data
))) {
937 /* u.ustuck name was saved above in case we're changing from can-see
938 to can't-see; but might have changed from can't-see to can-see so
939 override here if hero knows who u.ustuck is */
940 if (canspotmon(u
.ustuck
))
941 Strcpy(ustuckNam
, Monnam(u
.ustuck
));
942 set_ustuck((struct monst
*) 0);
943 pline("%s loses its grip on you.", ustuckNam
);
944 } else if (sticking
&& !sticks(gy
.youmonst
.data
)) {
945 /* was holding onto u.ustuck but no longer capable of that */
950 if (touch_petrifies(u
.usteed
->data
) && !Stone_resistance
&& rnl(3)) {
951 pline("%s touch %s.", no_longer_petrify_resistant
,
953 Sprintf(buf
, "riding %s",
954 an(pmname(u
.usteed
->data
, Mgender(u
.usteed
))));
957 if (!can_ride(u
.usteed
))
958 dismount_steed(DISMOUNT_POLY
);
962 if (((!Levitation
&& !u
.ustuck
&& !Flying
&& is_pool_or_lava(u
.ux
, u
.uy
))
963 || (Underwater
&& !Swimming
))
964 /* if expelled above, expels() already called spoteffects() */
967 /* FIXME? if spoteffects() triggered rehumanize then we should
970 if (Passes_walls
&& u
.utrap
971 && (u
.utraptype
== TT_INFLOOR
|| u
.utraptype
== TT_BURIEDBALL
)) {
972 if (u
.utraptype
== TT_INFLOOR
) {
973 pline_The("rock seems to no longer trap you.");
975 pline_The("buried ball is no longer bound to you.");
976 buried_ball_to_freedom();
979 } else if (likes_lava(gy
.youmonst
.data
) && u
.utrap
980 && u
.utraptype
== TT_LAVA
) {
981 pline_The("%s now feels soothing.", hliquid("lava"));
984 if (amorphous(gy
.youmonst
.data
) || is_whirly(gy
.youmonst
.data
)
985 || unsolid(gy
.youmonst
.data
)) {
987 You("slip out of the iron chain.");
989 } else if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
) {
990 You("slip free of the buried ball and chain.");
991 buried_ball_to_freedom();
994 if (u
.utrap
&& (u
.utraptype
== TT_WEB
|| u
.utraptype
== TT_BEARTRAP
)
995 && (amorphous(gy
.youmonst
.data
) || is_whirly(gy
.youmonst
.data
)
996 || unsolid(gy
.youmonst
.data
)
997 || (gy
.youmonst
.data
->msize
<= MZ_SMALL
998 && u
.utraptype
== TT_BEARTRAP
))) {
999 You("are no longer stuck in the %s.",
1000 u
.utraptype
== TT_WEB
? "web" : "bear trap");
1001 /* probably should burn webs too if PM_FIRE_ELEMENTAL */
1004 if (webmaker(gy
.youmonst
.data
) && u
.utrap
&& u
.utraptype
== TT_WEB
) {
1005 You("orient yourself on the web.");
1008 check_strangling(TRUE
); /* maybe start strangling */
1011 gv
.vision_full_recalc
= 1;
1013 (void) encumber_msg();
1015 retouch_equipment(2);
1016 /* this might trigger a recursive call to polymon() [stone golem
1017 wielding cockatrice corpse and hit by stone-to-flesh, becomes
1018 flesh golem above, now gets transformed back into stone golem;
1019 fortunately neither form uses #monster] */
1021 selftouch(no_longer_petrify_resistant
);
1023 /* the explanation of '#monster' used to be shown sooner, but there are
1024 possible fatalities above and it isn't useful unless hero survives */
1025 if (flags
.verbose
) {
1026 static const char use_thec
[] = "Use the command #%s to %s.";
1027 static const char monsterc
[] = "monster";
1028 struct permonst
*uptr
= gy
.youmonst
.data
;
1029 boolean might_hide
= (is_hider(uptr
) || hides_under(uptr
));
1031 if (can_breathe(uptr
))
1032 pline(use_thec
, monsterc
, "use your breath weapon");
1033 if (attacktype(uptr
, AT_SPIT
))
1034 pline(use_thec
, monsterc
, "spit venom");
1035 if (uptr
->mlet
== S_NYMPH
)
1036 pline(use_thec
, monsterc
, "remove an iron ball");
1037 if (attacktype(uptr
, AT_GAZE
))
1038 pline(use_thec
, monsterc
, "gaze at monsters");
1039 if (might_hide
&& webmaker(uptr
))
1040 pline(use_thec
, monsterc
, "hide or to spin a web");
1041 else if (might_hide
)
1042 pline(use_thec
, monsterc
, "hide");
1043 else if (webmaker(uptr
))
1044 pline(use_thec
, monsterc
, "spin a web");
1046 pline(use_thec
, monsterc
, "summon help");
1047 if (u
.umonnum
== PM_GREMLIN
)
1048 pline(use_thec
, monsterc
, "multiply in a fountain");
1049 if (is_unicorn(uptr
))
1050 pline(use_thec
, monsterc
, "use your horn");
1051 if (is_mind_flayer(uptr
))
1052 pline(use_thec
, monsterc
, "emit a mental blast");
1053 if (uptr
->msound
== MS_SHRIEK
) /* worthless, actually */
1054 pline(use_thec
, monsterc
, "shriek");
1055 if (is_vampire(uptr
) || is_vampshifter(&gy
.youmonst
))
1056 pline(use_thec
, monsterc
, "change shape");
1058 if (lays_eggs(uptr
) && flags
.female
1059 && !(uptr
== &mons
[PM_GIANT_EEL
]
1060 || uptr
== &mons
[PM_ELECTRIC_EEL
]))
1061 pline(use_thec
, "sit",
1062 eggs_in_water(uptr
) ? "spawn in the water" : "lay an egg");
1067 /* determine hero's temporary strength value used while polymorphed;
1068 hero poly'd into M2_STRONG monster usually gets 18/100 strength but
1069 there are exceptions; non-M2_STRONG get maximum strength set to 18 */
1073 const struct Race
*R
;
1075 int mndx
= u
.umonnum
;
1076 struct permonst
*ptr
= &mons
[mndx
];
1079 if (mndx
!= PM_URUK_HAI
&& mndx
!= PM_ORC_CAPTAIN
)
1081 } else if (is_elf(ptr
)) {
1083 } else if (is_dwarf(ptr
)) {
1085 } else if (is_gnome(ptr
)) {
1087 #if 0 /* use the mons[] value for humans */
1088 } else if (is_human(ptr
)) {
1092 R
= character_race(mndx
);
1094 if (strongmonst(ptr
)) {
1095 /* ettins, titans and minotaurs don't pass the is_giant() test;
1096 giant mummies and giant zombies do but we throttle those */
1097 boolean live_H
= is_giant(ptr
) && !is_undead(ptr
);
1099 /* hero orcs are limited to 18/50 for maximum strength, so treat
1100 hero poly'd into an orc the same; goblins, orc shamans, and orc
1101 zombies don't have strongmonst() attribute so won't get here;
1102 hobgoblins and orc mummies do get here and are limited to 18/50
1103 like normal orcs; however, orc captains and Uruk-hai retain 18/100
1104 strength; hero gnomes are also limited to 18/50; hero elves are
1105 limited to 18/00 regardless of whether they're strongmonst, but
1106 the two strongmonst types (monarchs and nobles) have current
1107 strength set to 18 [by polymon()], the others don't */
1108 newMaxStr
= R
? R
->attrmax
[A_STR
] : live_H
? STR19(19) : STR18(100);
1110 newMaxStr
= R
? R
->attrmax
[A_STR
] : 18; /* 18 is same as STR18(0) */
1112 return (schar
) newMaxStr
;
1115 /* dropx() jacket for break_armor() */
1117 dropp(struct obj
*obj
)
1122 * Dropping worn armor while polymorphing might put hero into water
1123 * (loss of levitation boots or water walking boots that the new
1124 * form can't wear), where emergency_disrobe() could remove it from
1125 * inventory. Without this, dropx() could trigger an 'object lost'
1126 * panic. Right now, boots are the only armor which might encounter
1127 * this situation, but handle it for all armor.
1129 * Hypothetically, 'obj' could have merged with something (not
1130 * applicable for armor) and no longer be a valid pointer, so scan
1131 * inventory for it instead of trusting obj->where.
1133 for (otmp
= gi
.invent
; otmp
; otmp
= otmp
->nobj
) {
1136 /* Note that otmp->nobj is pointing at fobj now,
1138 * dropx() -> dropy() -> dropz() -> place_object(),
1139 * and no longer pointing at the next obj in inventory.
1140 * That would be an issue if this loop were allowed
1141 * to continue, but the break statement that
1142 * follows prevents the loop from continuing on with
1143 * objects on the floor.
1154 struct permonst
*uptr
= gy
.youmonst
.data
;
1156 if (breakarm(uptr
)) {
1157 if ((otmp
= uarm
) != 0) {
1160 /* for gold DSM, we don't want Armor_gone() to report that it
1161 stops shining _after_ we've been told that it is destroyed */
1163 end_burn(otmp
, FALSE
);
1165 You("break out of your armor!");
1166 exercise(A_STR
, FALSE
);
1167 (void) Armor_gone();
1170 if ((otmp
= uarmc
) != 0
1171 /* mummy wrapping adapts to small and very big sizes */
1172 && (otmp
->otyp
!= MUMMY_WRAPPING
|| !WrappingAllowed(uptr
))) {
1173 if (otmp
->oartifact
) {
1174 Your("%s falls off!", cloak_simple_name(otmp
));
1178 Your("%s tears apart!", cloak_simple_name(otmp
));
1184 Your("shirt rips to shreds!");
1187 } else if (sliparm(uptr
)) {
1188 if ((otmp
= uarm
) != 0 && racial_exception(&gy
.youmonst
, otmp
) < 1) {
1191 Your("armor falls around you!");
1192 /* [note: _gone() instead of _off() dates to when life-saving
1193 could force fire resisting armor back on if hero burned in
1194 hell (3.0, predating Gehennom); the armor isn't actually
1195 gone here but also isn't available to be put back on] */
1196 (void) Armor_gone();
1199 if ((otmp
= uarmc
) != 0
1200 /* mummy wrapping adapts to small and very big sizes */
1201 && (otmp
->otyp
!= MUMMY_WRAPPING
|| !WrappingAllowed(uptr
))) {
1202 if (is_whirly(uptr
))
1203 Your("%s falls, unsupported!", cloak_simple_name(otmp
));
1205 You("shrink out of your %s!", cloak_simple_name(otmp
));
1209 if ((otmp
= uarmu
) != 0) {
1210 if (is_whirly(uptr
))
1211 You("seep right through your shirt!");
1213 You("become much too small for your shirt!");
1214 setworn((struct obj
*) 0, otmp
->owornmask
& W_ARMU
);
1218 if (has_horns(uptr
)) {
1219 if ((otmp
= uarmh
) != 0) {
1220 if (is_flimsy(otmp
) && !donning(otmp
)) {
1221 char hornbuf
[BUFSZ
];
1223 /* Future possibilities: This could damage/destroy helmet */
1224 Sprintf(hornbuf
, "horn%s", plur(num_horns(uptr
)));
1225 Your("%s %s through %s.", hornbuf
, vtense(hornbuf
, "pierce"),
1230 Your("%s falls to the %s!", helm_simple_name(otmp
),
1231 surface(u
.ux
, u
.uy
));
1232 (void) Helmet_off();
1237 if (nohands(uptr
) || verysmall(uptr
)) {
1238 if ((otmp
= uarmg
) != 0) {
1241 /* Drop weapon along with gloves */
1242 You("drop your gloves%s!", uwep
? " and weapon" : "");
1244 (void) Gloves_off();
1245 /* Glib manipulation (ends immediately) handled by Gloves_off */
1248 if ((otmp
= uarms
) != 0) {
1249 You("can no longer hold your shield!");
1250 (void) Shield_off();
1253 if ((otmp
= uarmh
) != 0) {
1256 Your("%s falls to the %s!", helm_simple_name(otmp
),
1257 surface(u
.ux
, u
.uy
));
1258 (void) Helmet_off();
1262 if (nohands(uptr
) || verysmall(uptr
)
1263 || slithy(uptr
) || uptr
->mlet
== S_CENTAUR
) {
1264 if ((otmp
= uarmf
) != 0) {
1267 if (is_whirly(uptr
))
1268 Your("boots fall away!");
1270 Your("boots %s off your feet!",
1271 verysmall(uptr
) ? "slide" : "are pushed");
1276 /* not armor, but eyewear shouldn't stay worn without a head to wear
1277 it/them on (should also come off if head is too tiny or too huge,
1278 but putting accessories on doesn't reject those cases [yet?]);
1279 amulet stays worn */
1280 if ((otmp
= ublindf
) != 0 && !has_head(uptr
)) {
1282 const char *eyewear
= simpleonames(otmp
); /* blindfold|towel|lenses */
1284 if (!strncmp(eyewear
, "pair of ", l
= 8)) /* lenses */
1286 Your("%s %s off!", eyewear
, vtense(eyewear
, "fall"));
1287 (void) Blindf_off((struct obj
*) 0); /* Null: skip usual off mesg */
1290 /* rings stay worn even when no hands */
1294 drop_weapon(int alone
)
1297 const char *what
, *which
, *whichtoo
;
1298 boolean candropwep
, candropswapwep
, updateinv
= TRUE
;
1301 /* !alone check below is currently superfluous but in the
1302 * future it might not be so if there are monsters which cannot
1303 * wear gloves but can wield weapons
1305 if (!alone
|| cantwield(gy
.youmonst
.data
)) {
1306 candropwep
= canletgo(uwep
, "");
1307 candropswapwep
= !u
.twoweap
|| canletgo(uswapwep
, "");
1309 what
= (candropwep
&& candropswapwep
) ? "drop" : "release";
1310 which
= is_sword(uwep
) ? "sword" : weapon_descr(uwep
);
1313 is_sword(uswapwep
) ? "sword" : weapon_descr(uswapwep
);
1314 if (strcmp(which
, whichtoo
))
1317 if (uwep
->quan
!= 1L || u
.twoweap
)
1318 which
= makeplural(which
);
1320 You("find you must %s %s %s!", what
,
1321 the_your
[!!strncmp(which
, "corpse", 6)], which
);
1323 /* if either uwep or wielded uswapwep is flagged as 'in_use'
1324 then don't drop it or explicitly update inventory; leave
1325 those actions to caller (or caller's caller, &c) */
1331 else if (candropswapwep
)
1338 else if (candropwep
)
1340 /* [note: dropp vs dropx -- if heart of ahriman is wielded, we
1341 might be losing levitation by dropping it; but that won't
1342 happen until the drop, unlike Boots_off() dumping hero into
1343 water and triggering emergency_disrobe() before dropx()] */
1347 } else if (!could_twoweap(gy
.youmonst
.data
)) {
1353 /* return to original form, usually either due to polymorph timing out
1354 or dying from loss of hit points while being polymorphed */
1358 boolean was_flying
= (Flying
!= 0);
1360 /* You can't revert back while unchanging */
1363 svk
.killer
.format
= NO_KILLER_PREFIX
;
1364 Strcpy(svk
.killer
.name
, "killed while stuck in creature form");
1366 /* can get to here if declining to die in explore or wizard
1367 mode; since we're wearing an amulet of unchanging we can't
1368 be wearing an amulet of life-saving */
1369 return; /* don't rehumanize after all */
1370 } else if (uamul
&& uamul
->otyp
== AMULET_OF_UNCHANGING
) {
1371 Your("%s %s!", simpleonames(uamul
), otense(uamul
, "fail"));
1373 makeknown(AMULET_OF_UNCHANGING
);
1378 * Right now, dying while being a shifted vampire (bat, cloud, wolf)
1379 * reverts to human rather than to vampire.
1382 if (emits_light(gy
.youmonst
.data
))
1383 del_light_source(LS_MONSTER
, monst_to_any(&gy
.youmonst
));
1384 polyman("You return to %s form!", gu
.urace
.adj
);
1387 /* can only happen if some bit of code reduces u.uhp
1388 instead of u.mh while poly'd */
1389 Your("old form was not healthy enough to survive.");
1390 Sprintf(svk
.killer
.name
, "reverting to unhealthy %s form",
1392 svk
.killer
.format
= KILLED_BY
;
1398 gv
.vision_full_recalc
= 1;
1399 (void) encumber_msg();
1400 if (was_flying
&& !Flying
&& u
.usteed
)
1401 You("and %s return gently to the %s.",
1402 mon_nam(u
.usteed
), surface(u
.ux
, u
.uy
));
1403 retouch_equipment(2);
1405 selftouch(no_longer_petrify_resistant
);
1411 struct attack
*mattk
;
1414 You_cant("breathe. Sorry.");
1418 You("don't have enough energy to breathe!");
1424 if (!getdir((char *) 0))
1427 mattk
= attacktype_fordmg(gy
.youmonst
.data
, AT_BREA
, AD_ANY
);
1429 impossible("bad breath attack?"); /* mouthwash needed... */
1430 else if (!u
.dx
&& !u
.dy
&& !u
.dz
)
1433 ubuzz(BZ_U_BREATH(BZ_OFS_AD(mattk
->adtyp
)), (int) mattk
->damn
);
1441 struct attack
*mattk
;
1443 if (!getdir((char *) 0))
1445 mattk
= attacktype_fordmg(gy
.youmonst
.data
, AT_SPIT
, AD_ANY
);
1447 impossible("bad spit attack?");
1449 switch (mattk
->adtyp
) {
1452 otmp
= mksobj(BLINDING_VENOM
, TRUE
, FALSE
);
1455 impossible("bad attack type in dospit");
1459 otmp
= mksobj(ACID_VENOM
, TRUE
, FALSE
);
1462 otmp
->spe
= 1; /* to indicate it's yours */
1463 throwit(otmp
, 0L, FALSE
, (struct obj
*) 0);
1472 if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
) {
1473 pline_The("ball and chain are buried firmly in the %s.",
1474 surface(u
.ux
, u
.uy
));
1477 You("are not chained to anything!");
1487 coordxy x
= u
.ux
, y
= u
.uy
;
1488 struct trap
*ttmp
= t_at(x
, y
);
1489 /* disallow webs on water, lava, air & cloud */
1490 boolean reject_terrain
= is_pool_or_lava(x
, y
) || IS_AIR(levl
[x
][y
].typ
);
1492 /* [at the time this was written, it was not possible to be both a
1493 webmaker and a flyer, but with the advent of amulet of flying that
1494 became a possibility; at present hero can spin a web while flying] */
1495 if (Levitation
|| reject_terrain
) {
1496 You("must be on %s ground to spin a web.",
1497 reject_terrain
? "solid" : "the");
1501 You("release web fluid inside %s.", mon_nam(u
.ustuck
));
1502 if (is_animal(u
.ustuck
->data
)) {
1503 expels(u
.ustuck
, u
.ustuck
->data
, TRUE
);
1506 if (is_whirly(u
.ustuck
->data
)) {
1509 for (i
= 0; i
< NATTK
; i
++)
1510 if (u
.ustuck
->data
->mattk
[i
].aatyp
== AT_ENGL
)
1513 impossible("Swallower has no engulfing attack?");
1518 switch (u
.ustuck
->data
->mattk
[i
].adtyp
) {
1520 Strcpy(sweep
, "ignites and ");
1523 Strcpy(sweep
, "fries and ");
1526 Strcpy(sweep
, "freezes, shatters and ");
1529 pline_The("web %sis swept away!", sweep
);
1532 } /* default: a nasty jelly-like creature */
1533 pline_The("web dissolves into %s.", mon_nam(u
.ustuck
));
1537 You("cannot spin webs while stuck in a trap.");
1540 exercise(A_DEX
, TRUE
);
1542 switch (ttmp
->ttyp
) {
1545 You("spin a web, covering up the pit.");
1551 pline_The("squeaky board is muffled.");
1558 case VIBRATING_SQUARE
:
1559 Your("webbing vanishes!");
1562 You("make the web thicker.");
1566 You("web over the %s.",
1567 (ttmp
->ttyp
== TRAPDOOR
) ? "trap door" : "hole");
1571 case ROLLING_BOULDER_TRAP
:
1572 You("spin a web, jamming the trigger.");
1587 You("have triggered a trap!");
1588 dotrap(ttmp
, NO_TRAP_FLAGS
);
1591 impossible("Webbing over trap type %d?", ttmp
->ttyp
);
1594 } else if (On_stairs(x
, y
)) {
1595 /* cop out: don't let them hide the stairs */
1596 Your("web fails to impede access to the %s.",
1597 (levl
[x
][y
].typ
== STAIRS
) ? "stairs" : "ladder");
1600 ttmp
= maketrap(x
, y
, WEB
);
1605 if (*in_rooms(x
, y
, SHOPBASE
))
1606 add_damage(x
, y
, SHOP_WEB_COST
);
1616 You("lack the energy to send forth a call for help!");
1622 You("call upon your brethren for help!");
1623 exercise(A_WIS
, TRUE
);
1624 if (!were_summon(gy
.youmonst
.data
, TRUE
, &placeholder
, (char *) 0))
1625 pline("But none arrive.");
1638 for (i
= 0; i
< NATTK
; i
++) {
1639 if (gy
.youmonst
.data
->mattk
[i
].aatyp
== AT_GAZE
) {
1640 adtyp
= gy
.youmonst
.data
->mattk
[i
].adtyp
;
1644 if (adtyp
!= AD_CONF
&& adtyp
!= AD_FIRE
) {
1645 impossible("gaze attack %d?", adtyp
);
1650 You_cant("see anything to gaze at.");
1652 } else if (Hallucination
) {
1653 You_cant("gaze at anything you can see.");
1657 You("lack the energy to use your special gaze!");
1663 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
1664 if (DEADMONSTER(mtmp
))
1666 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
)) {
1668 if (Invis
&& !perceives(mtmp
->data
)) {
1669 pline("%s seems not to notice your gaze.", Monnam(mtmp
));
1670 } else if (mtmp
->minvis
&& !See_invisible
) {
1671 You_cant("see where to gaze at %s.", Monnam(mtmp
));
1672 } else if (M_AP_TYPE(mtmp
) == M_AP_FURNITURE
1673 || M_AP_TYPE(mtmp
) == M_AP_OBJECT
) {
1676 } else if (flags
.safe_dog
&& mtmp
->mtame
&& !Confusion
) {
1677 You("avoid gazing at %s.", y_monnam(mtmp
));
1679 if (flags
.confirm
&& mtmp
->mpeaceful
&& !Confusion
) {
1680 Sprintf(qbuf
, "Really %s %s?",
1681 (adtyp
== AD_CONF
) ? "confuse" : "attack",
1683 if (y_n(qbuf
) != 'y')
1686 setmangry(mtmp
, TRUE
);
1687 if (helpless(mtmp
) || mtmp
->mstun
1688 || !mtmp
->mcansee
|| !haseyes(mtmp
->data
)) {
1692 /* No reflection check for consistency with when a monster
1693 * gazes at *you*--only medusa gaze gets reflected then.
1695 if (adtyp
== AD_CONF
) {
1697 Your("gaze confuses %s!", mon_nam(mtmp
));
1699 pline("%s is getting more and more confused.",
1702 } else if (adtyp
== AD_FIRE
) {
1703 int dmg
= d(2, 6), orig_dmg
= dmg
, lev
= (int) u
.ulevel
;
1705 You("attack %s with a fiery gaze!", mon_nam(mtmp
));
1706 if (resists_fire(mtmp
)) {
1707 pline_The("fire doesn't burn %s!", mon_nam(mtmp
));
1710 if (lev
> rn2(20)) {
1711 dmg
+= destroy_items(mtmp
, AD_FIRE
, orig_dmg
);
1712 ignite_items(mtmp
->minvent
);
1716 if (DEADMONSTER(mtmp
))
1719 /* For consistency with passive() in uhitm.c, this only
1720 * affects you if the monster is still alive.
1722 if (DEADMONSTER(mtmp
))
1725 if (mtmp
->data
== &mons
[PM_FLOATING_EYE
] && !mtmp
->mcan
) {
1727 You("are frozen by %s gaze!",
1728 s_suffix(mon_nam(mtmp
)));
1729 nomul((u
.ulevel
> 6 || rn2(4))
1730 ? -d((int) mtmp
->m_lev
+ 1,
1731 (int) mtmp
->data
->mattk
[0].damd
)
1733 gm
.multi_reason
= "frozen by a monster's gaze";
1737 You("stiffen momentarily under %s gaze.",
1738 s_suffix(mon_nam(mtmp
)));
1740 /* Technically this one shouldn't affect you at all because
1741 * the Medusa gaze is an active monster attack that only
1742 * works on the monster's turn, but for it to *not* have an
1743 * effect would be too weird.
1745 if (mtmp
->data
== &mons
[PM_MEDUSA
] && !mtmp
->mcan
) {
1746 pline("Gazing at the awake %s is not a very good idea.",
1748 /* as if gazing at a sleeping anything is fruitful... */
1749 urgent_pline("You turn to stone...");
1750 svk
.killer
.format
= KILLED_BY
;
1751 Strcpy(svk
.killer
.name
,
1752 "deliberately meeting Medusa's gaze");
1759 You("gaze at no place in particular.");
1763 /* called by domonability() for #monster */
1767 boolean ismimic
= gy
.youmonst
.data
->mlet
== S_MIMIC
,
1768 on_ceiling
= is_clinger(gy
.youmonst
.data
) || Flying
;
1770 /* can't hide while being held (or holding) or while trapped
1771 (except for floor hiders [trapper or mimic] in pits) */
1772 if (u
.ustuck
|| (u
.utrap
&& (u
.utraptype
!= TT_PIT
|| on_ceiling
))) {
1773 You_cant("hide while you're %s.",
1774 !u
.ustuck
? "trapped"
1775 : u
.uswallow
? (digests(u
.ustuck
->data
) ? "swallowed"
1777 : !sticks(gy
.youmonst
.data
) ? "being held"
1778 : (humanoid(u
.ustuck
->data
) ? "holding someone"
1779 : "holding that creature"));
1780 if (u
.uundetected
|| (ismimic
&& U_AP_TYPE
!= M_AP_NOTHING
)) {
1782 gy
.youmonst
.m_ap_type
= M_AP_NOTHING
;
1787 /* note: hero-as-eel handling is incomplete but unnecessary;
1788 such critters aren't offered the option of hiding via #monster */
1789 if (gy
.youmonst
.data
->mlet
== S_EEL
&& !is_pool(u
.ux
, u
.uy
)) {
1790 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
))
1791 pline_The("fountain is not deep enough to hide in.");
1793 There("is no %s to hide in here.", hliquid("water"));
1797 if (hides_under(gy
.youmonst
.data
)) {
1799 struct obj
*otmp
, *otop
= svl
.level
.objects
[u
.ux
][u
.uy
];
1802 There("is nothing to hide under here.");
1807 otmp
&& otmp
->otyp
== CORPSE
1808 && touch_petrifies(&mons
[otmp
->corpsenm
]);
1809 otmp
= otmp
->nexthere
)
1811 /* otmp will be Null iff the entire pile consists of 'trice corpses */
1812 if (!otmp
&& !Stone_resistance
) {
1814 const char *corpse_name
= cxname(otop
);
1816 /* for the plural case, we'll say "cockatrice corpses" or
1817 "chickatrice corpses" depending on the top of the pile
1818 even if both types are present */
1820 corpse_name
= an(corpse_name
);
1821 /* no need to check poly_when_stoned(); no hide-underers can
1822 turn into stone golems instead of becoming petrified */
1823 pline("Hiding under %s%s is a fatal mistake...",
1824 corpse_name
, plur(ct
));
1825 Sprintf(kbuf
, "hiding under %s%s", corpse_name
, plur(ct
));
1827 /* only reach here if life-saved */
1832 /* Planes of Air and Water */
1833 if (on_ceiling
&& !has_ceiling(&u
.uz
)) {
1834 There("is nowhere to hide above you.");
1838 if ((is_hider(gy
.youmonst
.data
) && !Flying
) /* floor hider */
1839 && (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
))) {
1840 There("is nowhere to hide beneath you.");
1844 /* TODO? inhibit floor hiding at furniture locations, or
1845 * else make youhiding() give smarter messages at such spots.
1848 if (u
.uundetected
|| (ismimic
&& U_AP_TYPE
!= M_AP_NOTHING
)) {
1849 youhiding(FALSE
, 1); /* "you are already hiding" */
1854 /* should bring up a dialog "what would you like to imitate?" */
1855 gy
.youmonst
.m_ap_type
= M_AP_OBJECT
;
1856 gy
.youmonst
.mappearance
= STRANGE_OBJECT
;
1860 youhiding(FALSE
, 0); /* "you are now hiding" */
1867 struct permonst
*savedat
= gy
.youmonst
.data
;
1869 if (is_vampire(gy
.youmonst
.data
) || is_vampshifter(&gy
.youmonst
)) {
1870 polyself(POLY_MONSTER
);
1871 if (savedat
!= gy
.youmonst
.data
) {
1872 You("transform into %s.",
1873 an(pmname(gy
.youmonst
.data
, Ugender
)));
1880 /* #monster for hero-as-mind_flayer giving psychic blast */
1884 struct monst
*mtmp
, *nmon
;
1888 You("concentrate but lack the energy to maintain doing so.");
1894 You("concentrate.");
1895 pline("A wave of psychic energy pours out.");
1896 for (mtmp
= fmon
; mtmp
; mtmp
= nmon
) {
1900 if (DEADMONSTER(mtmp
))
1902 if (mdistu(mtmp
) > BOLT_LIM
* BOLT_LIM
)
1904 if (mtmp
->mpeaceful
)
1906 if (mindless(mtmp
->data
))
1908 u_sen
= telepathic(mtmp
->data
) && !mtmp
->mcansee
;
1909 if (u_sen
|| (telepathic(mtmp
->data
) && rn2(2)) || !rn2(10)) {
1911 /* wake it up first, to bring hidden monster out of hiding;
1912 but in case it is currently peaceful, don't make it hostile
1913 unless it will survive the psychic blast, otherwise hero
1914 would avoid the penalty for killing it while peaceful */
1915 wakeup(mtmp
, (dmg
> mtmp
->mhp
) ? TRUE
: FALSE
);
1916 You("lock in on %s %s.", s_suffix(mon_nam(mtmp
)),
1918 : telepathic(mtmp
->data
) ? "latent telepathy"
1921 if (DEADMONSTER(mtmp
))
1931 struct monst
*mtmp
= u
.ustuck
;
1934 impossible("uunstick: no ustuck?");
1937 set_ustuck((struct monst
*) 0); /* before pline() */
1938 pline("%s is no longer in your clutches.", Monnam(mtmp
));
1942 skinback(boolean silently
)
1945 int old_light
= arti_light_radius(uskin
);
1948 Your("skin returns to its original form.");
1950 uskin
= (struct obj
*) 0;
1951 /* undo save/restore hack */
1952 uarm
->owornmask
&= ~I_SPECIAL
;
1954 if (artifact_light(uarm
))
1955 maybe_adjust_light(uarm
, old_light
);
1960 mbodypart(struct monst
*mon
, int part
)
1962 static NEARDATA
const char
1963 *humanoid_parts
[] = { "arm", "eye", "face", "finger",
1964 "fingertip", "foot", "hand", "handed",
1965 "head", "leg", "light headed", "neck",
1966 "spine", "toe", "hair", "blood",
1967 "lung", "nose", "stomach" },
1968 *jelly_parts
[] = { "pseudopod", "dark spot", "front",
1969 "pseudopod extension", "pseudopod extremity",
1970 "pseudopod root", "grasp", "grasped",
1971 "cerebral area", "lower pseudopod", "viscous",
1972 "middle", "surface", "pseudopod extremity",
1973 "ripples", "juices", "surface", "sensor",
1975 *animal_parts
[] = { "forelimb", "eye", "face",
1976 "foreclaw", "claw tip", "rear claw",
1977 "foreclaw", "clawed", "head",
1978 "rear limb", "light headed", "neck",
1979 "spine", "rear claw tip", "fur",
1980 "blood", "lung", "nose",
1982 *bird_parts
[] = { "wing", "eye", "face", "wing",
1983 "wing tip", "foot", "wing", "winged",
1984 "head", "leg", "light headed", "neck",
1985 "spine", "toe", "feathers", "blood",
1986 "lung", "bill", "stomach" },
1987 *horse_parts
[] = { "foreleg", "eye", "face",
1988 "forehoof", "hoof tip", "rear hoof",
1989 "forehoof", "hooved", "head",
1990 "rear leg", "light headed", "neck",
1991 "backbone", "rear hoof tip", "mane",
1992 "blood", "lung", "nose",
1994 *sphere_parts
[] = { "appendage", "optic nerve", "body", "tentacle",
1995 "tentacle tip", "lower appendage", "tentacle",
1996 "tentacled", "body", "lower tentacle",
1997 "rotational", "equator", "body",
1998 "lower tentacle tip", "cilia", "life force",
1999 "retina", "olfactory nerve", "interior" },
2000 *fungus_parts
[] = { "mycelium", "visual area", "front",
2001 "hypha", "hypha", "root",
2002 "strand", "stranded", "cap area",
2003 "rhizome", "sporulated", "stalk",
2004 "root", "rhizome tip", "spores",
2005 "juices", "gill", "gill",
2007 *vortex_parts
[] = { "region", "eye", "front",
2008 "minor current", "minor current", "lower current",
2009 "swirl", "swirled", "central core",
2010 "lower current", "addled", "center",
2011 "currents", "edge", "currents",
2012 "life force", "center", "leading edge",
2014 *snake_parts
[] = { "vestigial limb", "eye", "face", "large scale",
2015 "large scale tip", "rear region", "scale gap",
2016 "scale gapped", "head", "rear region",
2017 "light headed", "neck", "length", "rear scale",
2018 "scales", "blood", "lung", "forked tongue",
2020 *worm_parts
[] = { "anterior segment", "light sensitive cell",
2021 "clitellum", "setae", "setae", "posterior segment",
2022 "segment", "segmented", "anterior segment",
2023 "posterior", "over stretched", "clitellum",
2024 "length", "posterior setae", "setae", "blood",
2025 "skin", "prostomium", "stomach" },
2026 *spider_parts
[] = { "pedipalp", "eye", "face", "pedipalp", "tarsus",
2027 "claw", "pedipalp", "palped", "cephalothorax",
2028 "leg", "spun out", "cephalothorax", "abdomen",
2029 "claw", "hair", "hemolymph", "book lung",
2030 "labrum", "digestive tract" },
2031 *fish_parts
[] = { "fin", "eye", "premaxillary", "pelvic axillary",
2032 "pelvic fin", "anal fin", "pectoral fin", "finned",
2033 "head", "peduncle", "played out", "gills",
2034 "dorsal fin", "caudal fin", "scales", "blood",
2035 "gill", "nostril", "stomach" };
2036 /* claw attacks are overloaded in mons[]; most humanoids with
2037 such attacks should still reference hands rather than claws */
2038 static const char not_claws
[] = {
2039 S_HUMAN
, S_MUMMY
, S_ZOMBIE
, S_ANGEL
, S_NYMPH
, S_LEPRECHAUN
,
2040 S_QUANTMECH
, S_VAMPIRE
, S_ORC
, S_GIANT
, /* quest nemeses */
2041 '\0' /* string terminator; assert( S_xxx != 0 ); */
2043 struct permonst
*mptr
= mon
->data
;
2045 if (part
<= NO_PART
) {
2046 impossible("mbodypart: bad part %d", part
);
2047 return "mystery part";
2050 /* some special cases */
2051 if (mptr
->mlet
== S_DOG
|| mptr
->mlet
== S_FELINE
2052 || mptr
->mlet
== S_RODENT
|| mptr
== &mons
[PM_OWLBEAR
]) {
2062 return horse_parts
[part
]; /* "foreleg", "rear leg" */
2064 break; /* for other parts, use animal_parts[] below */
2066 } else if (mptr
->mlet
== S_YETI
) { /* excl. owlbear due to 'if' above */
2067 /* opposable thumbs, hence "hands", "arms", "legs", &c */
2068 return humanoid_parts
[part
]; /* yeti/sasquatch, monkey/ape */
2070 if ((part
== HAND
|| part
== HANDED
)
2071 && (humanoid(mptr
) && attacktype(mptr
, AT_CLAW
)
2072 && !strchr(not_claws
, mptr
->mlet
) && mptr
!= &mons
[PM_STONE_GOLEM
]
2073 && mptr
!= &mons
[PM_AMOROUS_DEMON
]))
2074 return (part
== HAND
) ? "claw" : "clawed";
2075 if ((mptr
== &mons
[PM_MUMAK
] || mptr
== &mons
[PM_MASTODON
])
2078 if (mptr
== &mons
[PM_SHARK
] && part
== HAIR
)
2079 return "skin"; /* sharks don't have scales */
2080 if ((mptr
== &mons
[PM_JELLYFISH
] || mptr
== &mons
[PM_KRAKEN
])
2081 && (part
== ARM
|| part
== FINGER
|| part
== HAND
|| part
== FOOT
2084 if (mptr
== &mons
[PM_FLOATING_EYE
] && part
== EYE
)
2086 if (humanoid(mptr
) && (part
== ARM
|| part
== FINGER
|| part
== FINGERTIP
2087 || part
== HAND
|| part
== HANDED
))
2088 return humanoid_parts
[part
];
2089 if (mptr
->mlet
== S_COCKATRICE
)
2090 return (part
== HAIR
) ? snake_parts
[part
] : bird_parts
[part
];
2091 if (mptr
== &mons
[PM_RAVEN
])
2092 return bird_parts
[part
];
2093 if (mptr
->mlet
== S_CENTAUR
|| mptr
->mlet
== S_UNICORN
2094 || mptr
== &mons
[PM_KI_RIN
]
2095 || (mptr
== &mons
[PM_ROTHE
] && part
!= HAIR
))
2096 return horse_parts
[part
];
2097 if (mptr
->mlet
== S_LIGHT
) {
2100 else if (part
== ARM
|| part
== FINGER
|| part
== FINGERTIP
2106 if (mptr
== &mons
[PM_STALKER
] && part
== HEAD
)
2108 if (mptr
->mlet
== S_EEL
&& mptr
!= &mons
[PM_JELLYFISH
])
2109 return fish_parts
[part
];
2110 if (mptr
->mlet
== S_WORM
)
2111 return worm_parts
[part
];
2112 if (mptr
->mlet
== S_SPIDER
)
2113 return spider_parts
[part
];
2114 if (slithy(mptr
) || (mptr
->mlet
== S_DRAGON
&& part
== HAIR
))
2115 return snake_parts
[part
];
2116 if (mptr
->mlet
== S_EYE
)
2117 return sphere_parts
[part
];
2118 if (mptr
->mlet
== S_JELLY
|| mptr
->mlet
== S_PUDDING
2119 || mptr
->mlet
== S_BLOB
|| mptr
== &mons
[PM_JELLYFISH
])
2120 return jelly_parts
[part
];
2121 if (mptr
->mlet
== S_VORTEX
|| mptr
->mlet
== S_ELEMENTAL
)
2122 return vortex_parts
[part
];
2123 if (mptr
->mlet
== S_FUNGUS
)
2124 return fungus_parts
[part
];
2126 return humanoid_parts
[part
];
2127 return animal_parts
[part
];
2133 return mbodypart(&gy
.youmonst
, part
);
2139 /* Returns gender of polymorphed player;
2140 * 0/1=same meaning as flags.female, 2=none.
2142 if (is_neuter(gy
.youmonst
.data
) || !humanoid(gy
.youmonst
.data
))
2144 return flags
.female
;
2148 ugolemeffects(int damtype
, int dam
)
2152 /* We won't bother with "slow"/"haste" since players do not
2153 * have a monster-specific slow/haste so there is no way to
2154 * restore the old velocity once they are back to human.
2156 if (u
.umonnum
!= PM_FLESH_GOLEM
&& u
.umonnum
!= PM_IRON_GOLEM
)
2160 if (u
.umonnum
== PM_FLESH_GOLEM
)
2161 heal
= (dam
+ 5) / 6; /* Approx 1 per die */
2164 if (u
.umonnum
== PM_IRON_GOLEM
)
2168 if (heal
&& (u
.mh
< u
.mhmax
)) {
2173 pline("Strangely, you feel better than before.");
2174 exercise(A_STR
, TRUE
);
2179 armor_to_dragon(int atyp
)
2182 case GRAY_DRAGON_SCALE_MAIL
:
2183 case GRAY_DRAGON_SCALES
:
2184 return PM_GRAY_DRAGON
;
2185 case SILVER_DRAGON_SCALE_MAIL
:
2186 case SILVER_DRAGON_SCALES
:
2187 return PM_SILVER_DRAGON
;
2188 case GOLD_DRAGON_SCALE_MAIL
:
2189 case GOLD_DRAGON_SCALES
:
2190 return PM_GOLD_DRAGON
;
2191 #if 0 /* DEFERRED */
2192 case SHIMMERING_DRAGON_SCALE_MAIL
:
2193 case SHIMMERING_DRAGON_SCALES
:
2194 return PM_SHIMMERING_DRAGON
;
2196 case RED_DRAGON_SCALE_MAIL
:
2197 case RED_DRAGON_SCALES
:
2198 return PM_RED_DRAGON
;
2199 case ORANGE_DRAGON_SCALE_MAIL
:
2200 case ORANGE_DRAGON_SCALES
:
2201 return PM_ORANGE_DRAGON
;
2202 case WHITE_DRAGON_SCALE_MAIL
:
2203 case WHITE_DRAGON_SCALES
:
2204 return PM_WHITE_DRAGON
;
2205 case BLACK_DRAGON_SCALE_MAIL
:
2206 case BLACK_DRAGON_SCALES
:
2207 return PM_BLACK_DRAGON
;
2208 case BLUE_DRAGON_SCALE_MAIL
:
2209 case BLUE_DRAGON_SCALES
:
2210 return PM_BLUE_DRAGON
;
2211 case GREEN_DRAGON_SCALE_MAIL
:
2212 case GREEN_DRAGON_SCALES
:
2213 return PM_GREEN_DRAGON
;
2214 case YELLOW_DRAGON_SCALE_MAIL
:
2215 case YELLOW_DRAGON_SCALES
:
2216 return PM_YELLOW_DRAGON
;
2222 /* some species have awareness of other species */
2226 short warnidx
= NON_PM
;
2228 svc
.context
.warntype
.speciesidx
= NON_PM
;
2229 svc
.context
.warntype
.species
= 0;
2230 svc
.context
.warntype
.polyd
= 0;
2231 HWarn_of_mon
&= ~FROMRACE
;
2233 switch (u
.umonnum
) {
2234 case PM_PURPLE_WORM
:
2235 case PM_BABY_PURPLE_WORM
:
2236 warnidx
= PM_SHRIEKER
;
2239 case PM_VAMPIRE_LEADER
:
2240 svc
.context
.warntype
.polyd
= M2_HUMAN
| M2_ELF
;
2241 HWarn_of_mon
|= FROMRACE
;
2244 if (ismnum(warnidx
)) {
2245 svc
.context
.warntype
.speciesidx
= warnidx
;
2246 svc
.context
.warntype
.species
= &mons
[warnidx
];
2247 HWarn_of_mon
|= FROMRACE
;
2251 /* True iff hero's role or race has been genocided */
2255 return ((svm
.mvitals
[gu
.urole
.mnum
].mvflags
& G_GENOD
)
2256 || (svm
.mvitals
[gu
.urace
.mnum
].mvflags
& G_GENOD
));
2259 /* how hero feels "inside" after self-genocide of role or race */
2263 /* self-genocide used to always say "you feel dead inside" but that
2264 seems silly when you're polymorphed into something undead;
2265 monkilled() distinguishes between living (killed) and non (destroyed)
2266 for monster death message; we refine the nonliving aspect a bit */
2267 return !nonliving(gy
.youmonst
.data
)
2268 ? "dead" /* living, including demons */
2269 : !weirdnonliving(gy
.youmonst
.data
)
2270 ? "condemned" /* undead plus manes */
2271 : "empty"; /* golems plus vortices */