1 /* SCCS Id: @(#)polyself.c 3.4 2003/01/08 */
2 /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /*
6 * Polymorph self routine.
7 *
8 * Note: the light source handling code assumes that both youmonst.m_id
9 * and youmonst.mx will always remain 0 when it handles the case of the
10 * player polymorphed into a light-emitting monster.
11 */
12
13 #include "hack.h"
14
15 #ifdef OVLB
16 STATIC_DCL void FDECL(polyman, (const char *,const char *));
17 STATIC_DCL void NDECL(break_armor);
18 STATIC_DCL void FDECL(drop_weapon,(int));
19 STATIC_DCL void NDECL(uunstick);
20 STATIC_DCL int FDECL(armor_to_dragon,(int));
21 STATIC_DCL void NDECL(newman);
22
23 /* update the youmonst.data structure pointer */
24 void
set_uasmon()25 set_uasmon()
26 {
27 set_mon_data(&youmonst, &mons[u.umonnum], 0);
28 }
29
30 /* make a (new) human out of the player */
31 STATIC_OVL void
polyman(fmt,arg)32 polyman(fmt, arg)
33 const char *fmt, *arg;
34 {
35 boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
36 was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT);
37 boolean could_pass_walls = Passes_walls;
38 boolean was_blind = !!Blind;
39
40 if (Upolyd) {
41 u.acurr = u.macurr; /* restore old attribs */
42 u.amax = u.mamax;
43 u.umonnum = u.umonster;
44 flags.female = u.mfemale;
45 }
46 set_uasmon();
47
48 u.mh = u.mhmax = 0;
49 u.mtimedone = 0;
50 skinback(FALSE);
51 u.uundetected = 0;
52
53 if (sticky) uunstick();
54 find_ac();
55 if (was_mimicking) {
56 if (multi < 0) unmul("");
57 youmonst.m_ap_type = M_AP_NOTHING;
58 }
59
60 newsym(u.ux,u.uy);
61
62 You(fmt, arg);
63 /* check whether player foolishly genocided self while poly'd */
64 if ((mvitals[urole.malenum].mvflags & G_GENOD) ||
65 (urole.femalenum != NON_PM &&
66 (mvitals[urole.femalenum].mvflags & G_GENOD)) ||
67 (mvitals[urace.malenum].mvflags & G_GENOD) ||
68 (urace.femalenum != NON_PM &&
69 (mvitals[urace.femalenum].mvflags & G_GENOD))) {
70 /* intervening activity might have clobbered genocide info */
71 killer = delayed_killer;
72 if (!killer || !strstri(killer, "genocid")) {
73 killer_format = KILLED_BY;
74 killer = "self-genocide";
75 }
76 done(GENOCIDED);
77 }
78
79 if (u.twoweap && !could_twoweap(youmonst.data))
80 untwoweapon();
81
82 if (u.utraptype == TT_PIT) {
83 if (could_pass_walls) { /* player forms cannot pass walls */
84 u.utrap = rn1(6,2);
85 }
86 }
87 if (was_blind && !Blind) { /* reverting from eyeless */
88 Blinded = 1L;
89 make_blinded(0L, TRUE); /* remove blindness */
90 }
91
92 if(!Levitation && !u.ustuck &&
93 (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy)))
94 spoteffects(TRUE);
95
96 see_monsters();
97 }
98
99 void
change_sex()100 change_sex()
101 {
102 /* setting u.umonster for caveman/cavewoman or priest/priestess
103 swap unintentionally makes `Upolyd' appear to be true */
104 boolean already_polyd = (boolean) Upolyd;
105
106 /* Some monsters are always of one sex and their sex can't be changed */
107 /* succubi/incubi can change, but are handled below */
108 /* !already_polyd check necessary because is_male() and is_female()
109 are true if the player is a priest/priestess */
110 if (!already_polyd || (!is_male(youmonst.data) && !is_female(youmonst.data) && !is_neuter(youmonst.data)))
111 flags.female = !flags.female;
112 if (already_polyd) /* poly'd: also change saved sex */
113 u.mfemale = !u.mfemale;
114 max_rank_sz(); /* [this appears to be superfluous] */
115 if ((already_polyd ? u.mfemale : flags.female) && urole.name.f)
116 Strcpy(pl_character, urole.name.f);
117 else
118 Strcpy(pl_character, urole.name.m);
119 u.umonster = ((already_polyd ? u.mfemale : flags.female) && urole.femalenum != NON_PM) ?
120 urole.femalenum : urole.malenum;
121 if (!already_polyd) {
122 u.umonnum = u.umonster;
123 } else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) {
124 flags.female = !flags.female;
125 /* change monster type to match new sex */
126 u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS;
127 set_uasmon();
128 }
129 }
130
131 STATIC_OVL void
newman()132 newman()
133 {
134 int tmp, oldlvl;
135
136 tmp = u.uhpmax;
137 oldlvl = u.ulevel;
138 u.ulevel = u.ulevel + rn1(5, -2);
139 if (u.ulevel > 127 || u.ulevel < 1) { /* level went below 0? */
140 u.ulevel = oldlvl; /* restore old level in case they lifesave */
141 goto dead;
142 }
143 if (u.ulevel > MAXULEV) u.ulevel = MAXULEV;
144 /* If your level goes down, your peak level goes down by
145 the same amount so that you can't simply use blessed
146 full healing to undo the decrease. But if your level
147 goes up, your peak level does *not* undergo the same
148 adjustment; you might end up losing out on the chance
149 to regain some levels previously lost to other causes. */
150 if (u.ulevel < oldlvl) u.ulevelmax -= (oldlvl - u.ulevel);
151 if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
152
153 if (!rn2(10)) change_sex();
154
155 adjabil(oldlvl, (int)u.ulevel);
156 reset_rndmonst(NON_PM); /* new monster generation criteria */
157
158 /* random experience points for the new experience level */
159 u.uexp = rndexp(FALSE);
160
161 /* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level
162 * -10 and +10: don't apply proportionate HP to 10 of a starting
163 * character's hit points (since a starting character's hit points
164 * are not on the same scale with hit points obtained through level
165 * gain)
166 * 9 - rn2(19): random change of -9 to +9 hit points
167 */
168 #ifndef LINT
169 u.uhpmax = ((u.uhpmax - 10) * (long)u.ulevel / oldlvl + 10) +
170 (9 - rn2(19));
171 #endif
172
173 #ifdef LINT
174 u.uhp = u.uhp + tmp;
175 #else
176 u.uhp = u.uhp * (long)u.uhpmax/tmp;
177 #endif
178
179 tmp = u.uenmax;
180 #ifndef LINT
181 u.uenmax = u.uenmax * (long)u.ulevel / oldlvl + 9 - rn2(19);
182 #endif
183 if (u.uenmax < 0) u.uenmax = 0;
184 #ifndef LINT
185 u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax);
186 #endif
187
188 redist_attr();
189 u.uhunger = rn1(500,500);
190 if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
191 Stoned = 0;
192 delayed_killer = 0;
193 if (u.uhp <= 0 || u.uhpmax <= 0) {
194 if (Polymorph_control) {
195 if (u.uhp <= 0) u.uhp = 1;
196 if (u.uhpmax <= 0) u.uhpmax = 1;
197 } else {
198 dead: /* we come directly here if their experience level went to 0 or less */
199 Your("new form doesn't seem healthy enough to survive.");
200 killer_format = KILLED_BY_AN;
201 killer="unsuccessful polymorph";
202 done(DIED);
203 newuhs(FALSE);
204 return; /* lifesaved */
205 }
206 }
207 newuhs(FALSE);
208 polyman("feel like a new %s!",
209 (flags.female && urace.individual.f) ? urace.individual.f :
210 (urace.individual.m) ? urace.individual.m : urace.noun);
211 if (Slimed) {
212 Your("body transforms, but there is still slime on you.");
213 Slimed = 10L;
214 }
215 flags.botl = 1;
216 see_monsters();
217 (void) encumber_msg();
218 }
219
220 void
polyself(forcecontrol)221 polyself(forcecontrol)
222 boolean forcecontrol;
223 {
224 char buf[BUFSZ];
225 int old_light, new_light;
226 int mntmp = NON_PM;
227 int tries=0;
228 boolean draconian = (uarm &&
229 uarm->otyp >= GRAY_DRAGON_SCALE_MAIL &&
230 uarm->otyp <= YELLOW_DRAGON_SCALES);
231 boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data));
232 boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT);
233 boolean was_floating = (Levitation || Flying);
234
235 if(!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) {
236 if (rn2(20) > ACURR(A_CON)) {
237 You(shudder_for_moment);
238 losehp(rnd(30), "system shock", KILLED_BY_AN);
239 exercise(A_CON, FALSE);
240 return;
241 }
242 }
243 old_light = Upolyd ? emits_light(youmonst.data) : 0;
244
245 if (Polymorph_control || forcecontrol) {
246 do {
247 getlin("Become what kind of monster? [type the name]",
248 buf);
249 mntmp = name_to_mon(buf);
250 if (mntmp < LOW_PM)
251 pline("I've never heard of such monsters.");
252 /* Note: humans are illegal as monsters, but an
253 * illegal monster forces newman(), which is what we
254 * want if they specified a human.... */
255 else if (!polyok(&mons[mntmp]) && !your_race(&mons[mntmp]))
256 You("cannot polymorph into that.");
257 else break;
258 } while(++tries < 5);
259 if (tries==5) pline(thats_enough_tries);
260 /* allow skin merging, even when polymorph is controlled */
261 if (draconian &&
262 (mntmp == armor_to_dragon(uarm->otyp) || tries == 5))
263 goto do_merge;
264 } else if (draconian || iswere || isvamp) {
265 /* special changes that don't require polyok() */
266 if (draconian) {
267 do_merge:
268 mntmp = armor_to_dragon(uarm->otyp);
269 if (!(mvitals[mntmp].mvflags & G_GENOD)) {
270 /* allow G_EXTINCT */
271 You("merge with your scaly armor.");
272 uskin = uarm;
273 uarm = (struct obj *)0;
274 /* save/restore hack */
275 uskin->owornmask |= I_SPECIAL;
276 }
277 } else if (iswere) {
278 if (is_were(youmonst.data))
279 mntmp = PM_HUMAN; /* Illegal; force newman() */
280 else
281 mntmp = u.ulycn;
282 } else {
283 if (youmonst.data->mlet == S_VAMPIRE)
284 mntmp = PM_VAMPIRE_BAT;
285 else
286 mntmp = PM_VAMPIRE;
287 }
288 /* if polymon fails, "you feel" message has been given
289 so don't follow up with another polymon or newman */
290 if (mntmp == PM_HUMAN) newman(); /* werecritter */
291 else (void) polymon(mntmp);
292 goto made_change; /* maybe not, but this is right anyway */
293 }
294
295 if (mntmp < LOW_PM) {
296 tries = 0;
297 do {
298 /* randomly pick an "ordinary" monster */
299 mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
300 } while((!polyok(&mons[mntmp]) || is_placeholder(&mons[mntmp]))
301 && tries++ < 200);
302 }
303
304 /* The below polyok() fails either if everything is genocided, or if
305 * we deliberately chose something illegal to force newman().
306 */
307 if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp]))
308 newman();
309 else if(!polymon(mntmp)) return;
310
311 if (!uarmg) selftouch("No longer petrify-resistant, you");
312
313 made_change:
314 new_light = Upolyd ? emits_light(youmonst.data) : 0;
315 if (old_light != new_light) {
316 if (old_light)
317 del_light_source(LS_MONSTER, (genericptr_t)&youmonst);
318 if (new_light == 1) ++new_light; /* otherwise it's undetectable */
319 if (new_light)
320 new_light_source(u.ux, u.uy, new_light,
321 LS_MONSTER, (genericptr_t)&youmonst);
322 }
323 if (is_pool(u.ux,u.uy) && was_floating && !(Levitation || Flying) &&
324 !breathless(youmonst.data) && !amphibious(youmonst.data) &&
325 !Swimming) drown();
326 }
327
328 /* (try to) make a mntmp monster out of the player */
329 int
polymon(mntmp)330 polymon(mntmp) /* returns 1 if polymorph successful */
331 int mntmp;
332 {
333 boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
334 was_blind = !!Blind, dochange = FALSE;
335 boolean could_pass_walls = Passes_walls;
336 int mlvl;
337
338 if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */
339 You_feel("rather %s-ish.",mons[mntmp].mname);
340 exercise(A_WIS, TRUE);
341 return(0);
342 }
343
344 /* KMH, conduct */
345 u.uconduct.polyselfs++;
346
347 if (!Upolyd) {
348 /* Human to monster; save human stats */
349 u.macurr = u.acurr;
350 u.mamax = u.amax;
351 u.mfemale = flags.female;
352 } else {
353 /* Monster to monster; restore human stats, to be
354 * immediately changed to provide stats for the new monster
355 */
356 u.acurr = u.macurr;
357 u.amax = u.mamax;
358 flags.female = u.mfemale;
359 }
360
361 if (youmonst.m_ap_type) {
362 /* stop mimicking immediately */
363 if (multi < 0) unmul("");
364 } else if (mons[mntmp].mlet != S_MIMIC) {
365 /* as in polyman() */
366 youmonst.m_ap_type = M_AP_NOTHING;
367 }
368 if (is_male(&mons[mntmp])) {
369 if(flags.female) dochange = TRUE;
370 } else if (is_female(&mons[mntmp])) {
371 if(!flags.female) dochange = TRUE;
372 } else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) {
373 if(!rn2(10)) dochange = TRUE;
374 }
375 if (dochange) {
376 flags.female = !flags.female;
377 You("%s %s%s!",
378 (u.umonnum != mntmp) ? "turn into a" : "feel like a new",
379 (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" :
380 flags.female ? "female " : "male ",
381 mons[mntmp].mname);
382 } else {
383 if (u.umonnum != mntmp)
384 You("turn into %s!", an(mons[mntmp].mname));
385 else
386 You_feel("like a new %s!", mons[mntmp].mname);
387 }
388 if (Stoned && poly_when_stoned(&mons[mntmp])) {
389 /* poly_when_stoned already checked stone golem genocide */
390 You("turn to stone!");
391 mntmp = PM_STONE_GOLEM;
392 Stoned = 0;
393 delayed_killer = 0;
394 }
395
396 u.mtimedone = rn1(500, 500);
397 u.umonnum = mntmp;
398 set_uasmon();
399
400 /* New stats for monster, to last only as long as polymorphed.
401 * Currently only strength gets changed.
402 */
403 if(strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100);
404
405 if (Stone_resistance && Stoned) { /* parnes@eniac.seas.upenn.edu */
406 Stoned = 0;
407 delayed_killer = 0;
408 You("no longer seem to be petrifying.");
409 }
410 if (Sick_resistance && Sick) {
411 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
412 You("no longer feel sick.");
413 }
414 if (Slimed) {
415 if (flaming(youmonst.data)) {
416 pline_The("slime burns away!");
417 Slimed = 0L;
418 flags.botl = 1;
419 } else if (mntmp == PM_GREEN_SLIME) {
420 /* do it silently */
421 Slimed = 0L;
422 flags.botl = 1;
423 }
424 }
425 if (nohands(youmonst.data)) Glib = 0;
426
427 /*
428 mlvl = adj_lev(&mons[mntmp]);
429 * We can't do the above, since there's no such thing as an
430 * "experience level of you as a monster" for a polymorphed character.
431 */
432 mlvl = (int)mons[mntmp].mlevel;
433 if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) {
434 u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + d(mlvl,4));
435 } else if (is_golem(youmonst.data)) {
436 u.mhmax = golemhp(mntmp);
437 } else {
438 if (!mlvl) u.mhmax = rnd(4);
439 else u.mhmax = d(mlvl, 8);
440 if (is_home_elemental(&mons[mntmp])) u.mhmax *= 3;
441 }
442 u.mh = u.mhmax;
443
444 if (u.ulevel < mlvl) {
445 /* Low level characters can't become high level monsters for long */
446 #ifdef DUMB
447 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
448 int mtd = u.mtimedone, ulv = u.ulevel;
449
450 u.mtimedone = mtd * ulv / mlvl;
451 #else
452 u.mtimedone = u.mtimedone * u.ulevel / mlvl;
453 #endif
454 }
455
456 if (uskin && mntmp != armor_to_dragon(uskin->otyp))
457 skinback(FALSE);
458 break_armor();
459 drop_weapon(1);
460 if (hides_under(youmonst.data))
461 u.uundetected = OBJ_AT(u.ux, u.uy);
462 else if (youmonst.data->mlet == S_EEL)
463 u.uundetected = is_pool(u.ux, u.uy);
464 else
465 u.uundetected = 0;
466
467 if (u.utraptype == TT_PIT) {
468 if (could_pass_walls && !Passes_walls) {
469 u.utrap = rn1(6,2);
470 } else if (!could_pass_walls && Passes_walls) {
471 u.utrap = 0;
472 }
473 }
474 if (was_blind && !Blind) { /* previous form was eyeless */
475 Blinded = 1L;
476 make_blinded(0L, TRUE); /* remove blindness */
477 }
478 newsym(u.ux,u.uy); /* Change symbol */
479
480 if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0;
481 else if (sticky && !sticks(youmonst.data)) uunstick();
482 #ifdef STEED
483 if (u.usteed) {
484 if (touch_petrifies(u.usteed->data) &&
485 !Stone_resistance && rnl(3)) {
486 char buf[BUFSZ];
487
488 pline("No longer petrifying-resistant, you touch %s.",
489 mon_nam(u.usteed));
490 Sprintf(buf, "riding %s", an(u.usteed->data->mname));
491 instapetrify(buf);
492 }
493 if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY);
494 }
495 #endif
496
497 if (flags.verbose) {
498 static const char use_thec[] = "Use the command #%s to %s.";
499 static const char monsterc[] = "monster";
500 if (can_breathe(youmonst.data))
501 pline(use_thec,monsterc,"use your breath weapon");
502 if (attacktype(youmonst.data, AT_SPIT))
503 pline(use_thec,monsterc,"spit venom");
504 if (youmonst.data->mlet == S_NYMPH)
505 pline(use_thec,monsterc,"remove an iron ball");
506 if (attacktype(youmonst.data, AT_GAZE))
507 pline(use_thec,monsterc,"gaze at monsters");
508 if (is_hider(youmonst.data))
509 pline(use_thec,monsterc,"hide");
510 if (is_were(youmonst.data))
511 pline(use_thec,monsterc,"summon help");
512 if (webmaker(youmonst.data))
513 pline(use_thec,monsterc,"spin a web");
514 if (u.umonnum == PM_GREMLIN)
515 pline(use_thec,monsterc,"multiply in a fountain");
516 if (is_unicorn(youmonst.data))
517 pline(use_thec,monsterc,"use your horn");
518 if (is_mind_flayer(youmonst.data))
519 pline(use_thec,monsterc,"emit a mental blast");
520 if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */
521 pline(use_thec,monsterc,"shriek");
522 if (lays_eggs(youmonst.data) && flags.female)
523 pline(use_thec,"sit","lay an egg");
524 }
525 /* you now know what an egg of your type looks like */
526 if (lays_eggs(youmonst.data)) {
527 learn_egg_type(u.umonnum);
528 /* make queen bees recognize killer bee eggs */
529 learn_egg_type(egg_type_from_parent(u.umonnum, TRUE));
530 }
531 find_ac();
532 if((!Levitation && !u.ustuck && !Flying &&
533 (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) ||
534 (Underwater && !Swimming))
535 spoteffects(TRUE);
536 if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) {
537 u.utrap = 0;
538 pline_The("rock seems to no longer trap you.");
539 } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) {
540 u.utrap = 0;
541 pline_The("lava now feels soothing.");
542 }
543 if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
544 if (Punished) {
545 You("slip out of the iron chain.");
546 unpunish();
547 }
548 }
549 if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) &&
550 (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) ||
551 (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) {
552 You("are no longer stuck in the %s.",
553 u.utraptype == TT_WEB ? "web" : "bear trap");
554 /* probably should burn webs too if PM_FIRE_ELEMENTAL */
555 u.utrap = 0;
556 }
557 if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) {
558 You("orient yourself on the web.");
559 u.utrap = 0;
560 }
561 flags.botl = 1;
562 vision_full_recalc = 1;
563 see_monsters();
564 exercise(A_CON, FALSE);
565 exercise(A_WIS, TRUE);
566 (void) encumber_msg();
567 return(1);
568 }
569
570 STATIC_OVL void
break_armor()571 break_armor()
572 {
573 register struct obj *otmp;
574
575 if (breakarm(youmonst.data)) {
576 if ((otmp = uarm) != 0) {
577 if (donning(otmp)) cancel_don();
578 You("break out of your armor!");
579 exercise(A_STR, FALSE);
580 (void) Armor_gone();
581 useup(otmp);
582 }
583 if ((otmp = uarmc) != 0) {
584 if(otmp->oartifact) {
585 Your("%s falls off!", cloak_simple_name(otmp));
586 (void) Cloak_off();
587 dropx(otmp);
588 } else {
589 Your("%s tears apart!", cloak_simple_name(otmp));
590 (void) Cloak_off();
591 useup(otmp);
592 }
593 }
594 #ifdef TOURIST
595 if (uarmu) {
596 Your("shirt rips to shreds!");
597 useup(uarmu);
598 }
599 #endif
600 } else if (sliparm(youmonst.data)) {
601 if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) {
602 if (donning(otmp)) cancel_don();
603 Your("armor falls around you!");
604 (void) Armor_gone();
605 dropx(otmp);
606 }
607 if ((otmp = uarmc) != 0) {
608 if (is_whirly(youmonst.data))
609 Your("%s falls, unsupported!", cloak_simple_name(otmp));
610 else You("shrink out of your %s!", cloak_simple_name(otmp));
611 (void) Cloak_off();
612 dropx(otmp);
613 }
614 #ifdef TOURIST
615 if ((otmp = uarmu) != 0) {
616 if (is_whirly(youmonst.data))
617 You("seep right through your shirt!");
618 else You("become much too small for your shirt!");
619 setworn((struct obj *)0, otmp->owornmask & W_ARMU);
620 dropx(otmp);
621 }
622 #endif
623 }
624 if (has_horns(youmonst.data)) {
625 if ((otmp = uarmh) != 0) {
626 if (is_flimsy(otmp) && !donning(otmp)) {
627 char hornbuf[BUFSZ], yourbuf[BUFSZ];
628
629 /* Future possiblities: This could damage/destroy helmet */
630 Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data)));
631 Your("%s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"),
632 shk_your(yourbuf, otmp), xname(otmp));
633 } else {
634 if (donning(otmp)) cancel_don();
635 Your("helmet falls to the %s!", surface(u.ux, u.uy));
636 (void) Helmet_off();
637 dropx(otmp);
638 }
639 }
640 }
641 if (nohands(youmonst.data) || verysmall(youmonst.data)) {
642 if ((otmp = uarmg) != 0) {
643 if (donning(otmp)) cancel_don();
644 /* Drop weapon along with gloves */
645 You("drop your gloves%s!", uwep ? " and weapon" : "");
646 drop_weapon(0);
647 (void) Gloves_off();
648 dropx(otmp);
649 }
650 if ((otmp = uarms) != 0) {
651 You("can no longer hold your shield!");
652 (void) Shield_off();
653 dropx(otmp);
654 }
655 if ((otmp = uarmh) != 0) {
656 if (donning(otmp)) cancel_don();
657 Your("helmet falls to the %s!", surface(u.ux, u.uy));
658 (void) Helmet_off();
659 dropx(otmp);
660 }
661 }
662 if (nohands(youmonst.data) || verysmall(youmonst.data) ||
663 slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) {
664 if ((otmp = uarmf) != 0) {
665 if (donning(otmp)) cancel_don();
666 if (is_whirly(youmonst.data))
667 Your("boots fall away!");
668 else Your("boots %s off your feet!",
669 verysmall(youmonst.data) ? "slide" : "are pushed");
670 (void) Boots_off();
671 dropx(otmp);
672 }
673 }
674 }
675
676 STATIC_OVL void
drop_weapon(alone)677 drop_weapon(alone)
678 int alone;
679 {
680 struct obj *otmp;
681 struct obj *otmp2;
682
683 if ((otmp = uwep) != 0) {
684 /* !alone check below is currently superfluous but in the
685 * future it might not be so if there are monsters which cannot
686 * wear gloves but can wield weapons
687 */
688 if (!alone || cantwield(youmonst.data)) {
689 struct obj *wep = uwep;
690
691 if (alone) You("find you must drop your weapon%s!",
692 u.twoweap ? "s" : "");
693 otmp2 = u.twoweap ? uswapwep : 0;
694 uwepgone();
695 if (!wep->cursed || wep->otyp != LOADSTONE)
696 dropx(otmp);
697 if (otmp2 != 0) {
698 uswapwepgone();
699 if (!otmp2->cursed || otmp2->otyp != LOADSTONE)
700 dropx(otmp2);
701 }
702 untwoweapon();
703 } else if (!could_twoweap(youmonst.data)) {
704 untwoweapon();
705 }
706 }
707 }
708
709 void
rehumanize()710 rehumanize()
711 {
712 /* You can't revert back while unchanging */
713 if (Unchanging && (u.mh < 1)) {
714 killer_format = NO_KILLER_PREFIX;
715 killer = "killed while stuck in creature form";
716 done(DIED);
717 }
718
719 if (emits_light(youmonst.data))
720 del_light_source(LS_MONSTER, (genericptr_t)&youmonst);
721 polyman("return to %s form!", urace.adj);
722
723 if (u.uhp < 1) {
724 char kbuf[256];
725
726 Sprintf(kbuf, "reverting to unhealthy %s form", urace.adj);
727 killer_format = KILLED_BY;
728 killer = kbuf;
729 done(DIED);
730 }
731 if (!uarmg) selftouch("No longer petrify-resistant, you");
732 nomul(0);
733
734 flags.botl = 1;
735 vision_full_recalc = 1;
736 (void) encumber_msg();
737 }
738
739 int
dobreathe()740 dobreathe()
741 {
742 struct attack *mattk;
743
744 if (Strangled) {
745 You_cant("breathe. Sorry.");
746 return(0);
747 }
748 if (u.uen < 15) {
749 You("don't have enough energy to breathe!");
750 return(0);
751 }
752 u.uen -= 15;
753 flags.botl = 1;
754
755 if (!getdir((char *)0)) return(0);
756
757 mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY);
758 if (!mattk)
759 impossible("bad breath attack?"); /* mouthwash needed... */
760 else
761 buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn,
762 u.ux, u.uy, u.dx, u.dy);
763 return(1);
764 }
765
766 int
dospit()767 dospit()
768 {
769 struct obj *otmp;
770
771 if (!getdir((char *)0)) return(0);
772 otmp = mksobj(u.umonnum==PM_COBRA ? BLINDING_VENOM : ACID_VENOM,
773 TRUE, FALSE);
774 otmp->spe = 1; /* to indicate it's yours */
775 throwit(otmp, 0L, FALSE);
776 return(1);
777 }
778
779 int
doremove()780 doremove()
781 {
782 if (!Punished) {
783 You("are not chained to anything!");
784 return(0);
785 }
786 unpunish();
787 return(1);
788 }
789
790 int
dospinweb()791 dospinweb()
792 {
793 register struct trap *ttmp = t_at(u.ux,u.uy);
794
795 if (Levitation || Is_airlevel(&u.uz)
796 || Underwater || Is_waterlevel(&u.uz)) {
797 You("must be on the ground to spin a web.");
798 return(0);
799 }
800 if (u.uswallow) {
801 You("release web fluid inside %s.", mon_nam(u.ustuck));
802 if (is_animal(u.ustuck->data)) {
803 expels(u.ustuck, u.ustuck->data, TRUE);
804 return(0);
805 }
806 if (is_whirly(u.ustuck->data)) {
807 int i;
808
809 for (i = 0; i < NATTK; i++)
810 if (u.ustuck->data->mattk[i].aatyp == AT_ENGL)
811 break;
812 if (i == NATTK)
813 impossible("Swallower has no engulfing attack?");
814 else {
815 char sweep[30];
816
817 sweep[0] = '\0';
818 switch(u.ustuck->data->mattk[i].adtyp) {
819 case AD_FIRE:
820 Strcpy(sweep, "ignites and ");
821 break;
822 case AD_ELEC:
823 Strcpy(sweep, "fries and ");
824 break;
825 case AD_COLD:
826 Strcpy(sweep,
827 "freezes, shatters and ");
828 break;
829 }
830 pline_The("web %sis swept away!", sweep);
831 }
832 return(0);
833 } /* default: a nasty jelly-like creature */
834 pline_The("web dissolves into %s.", mon_nam(u.ustuck));
835 return(0);
836 }
837 if (u.utrap) {
838 You("cannot spin webs while stuck in a trap.");
839 return(0);
840 }
841 exercise(A_DEX, TRUE);
842 if (ttmp) switch (ttmp->ttyp) {
843 case PIT:
844 case SPIKED_PIT: You("spin a web, covering up the pit.");
845 deltrap(ttmp);
846 bury_objs(u.ux, u.uy);
847 newsym(u.ux, u.uy);
848 return(1);
849 case SQKY_BOARD: pline_The("squeaky board is muffled.");
850 deltrap(ttmp);
851 newsym(u.ux, u.uy);
852 return(1);
853 case TELEP_TRAP:
854 case LEVEL_TELEP:
855 case MAGIC_PORTAL:
856 Your("webbing vanishes!");
857 return(0);
858 case WEB: You("make the web thicker.");
859 return(1);
860 case HOLE:
861 case TRAPDOOR:
862 You("web over the %s.",
863 (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole");
864 deltrap(ttmp);
865 newsym(u.ux, u.uy);
866 return 1;
867 case ROLLING_BOULDER_TRAP:
868 You("spin a web, jamming the trigger.");
869 deltrap(ttmp);
870 newsym(u.ux, u.uy);
871 return(1);
872 case ARROW_TRAP:
873 case DART_TRAP:
874 case BEAR_TRAP:
875 case ROCKTRAP:
876 case FIRE_TRAP:
877 case LANDMINE:
878 case SLP_GAS_TRAP:
879 case RUST_TRAP:
880 case MAGIC_TRAP:
881 case ANTI_MAGIC:
882 case POLY_TRAP:
883 You("have triggered a trap!");
884 dotrap(ttmp, 0);
885 return(1);
886 default:
887 impossible("Webbing over trap type %d?", ttmp->ttyp);
888 return(0);
889 }
890 else if (On_stairs(u.ux, u.uy)) {
891 /* cop out: don't let them hide the stairs */
892 Your("web fails to impede access to the %s.",
893 (levl[u.ux][u.uy].typ == STAIRS) ? "stairs" : "ladder");
894 return(1);
895
896 }
897 ttmp = maketrap(u.ux, u.uy, WEB);
898 if (ttmp) {
899 ttmp->tseen = 1;
900 ttmp->madeby_u = 1;
901 }
902 newsym(u.ux, u.uy);
903 return(1);
904 }
905
906 int
dosummon()907 dosummon()
908 {
909 int placeholder;
910 if (u.uen < 10) {
911 You("lack the energy to send forth a call for help!");
912 return(0);
913 }
914 u.uen -= 10;
915 flags.botl = 1;
916
917 You("call upon your brethren for help!");
918 exercise(A_WIS, TRUE);
919 if (!were_summon(youmonst.data, TRUE, &placeholder, (char *)0))
920 pline("But none arrive.");
921 return(1);
922 }
923
924 int
dogaze()925 dogaze()
926 {
927 register struct monst *mtmp;
928 int looked = 0;
929 char qbuf[QBUFSZ];
930 int i;
931 uchar adtyp = 0;
932
933 for (i = 0; i < NATTK; i++) {
934 if(youmonst.data->mattk[i].aatyp == AT_GAZE) {
935 adtyp = youmonst.data->mattk[i].adtyp;
936 break;
937 }
938 }
939 if (adtyp != AD_CONF && adtyp != AD_FIRE) {
940 impossible("gaze attack %d?", adtyp);
941 return 0;
942 }
943
944
945 if (Blind) {
946 You_cant("see anything to gaze at.");
947 return 0;
948 }
949 if (u.uen < 15) {
950 You("lack the energy to use your special gaze!");
951 return(0);
952 }
953 u.uen -= 15;
954 flags.botl = 1;
955
956 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
957 if (DEADMONSTER(mtmp)) continue;
958 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
959 looked++;
960 if (Invis && !perceives(mtmp->data))
961 pline("%s seems not to notice your gaze.", Monnam(mtmp));
962 else if (mtmp->minvis && !See_invisible)
963 You_cant("see where to gaze at %s.", Monnam(mtmp));
964 else if (mtmp->m_ap_type == M_AP_FURNITURE
965 || mtmp->m_ap_type == M_AP_OBJECT) {
966 looked--;
967 continue;
968 } else if (flags.safe_dog && !Confusion && !Hallucination
969 && mtmp->mtame) {
970 You("avoid gazing at %s.", y_monnam(mtmp));
971 } else {
972 if (flags.confirm && mtmp->mpeaceful && !Confusion
973 && !Hallucination) {
974 Sprintf(qbuf, "Really %s %s?",
975 (adtyp == AD_CONF) ? "confuse" : "attack",
976 mon_nam(mtmp));
977 if (yn(qbuf) != 'y') continue;
978 setmangry(mtmp);
979 }
980 if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping ||
981 !mtmp->mcansee || !haseyes(mtmp->data)) {
982 looked--;
983 continue;
984 }
985 /* No reflection check for consistency with when a monster
986 * gazes at *you*--only medusa gaze gets reflected then.
987 */
988 if (adtyp == AD_CONF) {
989 if (!mtmp->mconf)
990 Your("gaze confuses %s!", mon_nam(mtmp));
991 else
992 pline("%s is getting more and more confused.",
993 Monnam(mtmp));
994 mtmp->mconf = 1;
995 } else if (adtyp == AD_FIRE) {
996 int dmg = d(2,6);
997 You("attack %s with a fiery gaze!", mon_nam(mtmp));
998 if (resists_fire(mtmp)) {
999 pline_The("fire doesn't burn %s!", mon_nam(mtmp));
1000 dmg = 0;
1001 }
1002 if((int) u.ulevel > rn2(20))
1003 (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
1004 if((int) u.ulevel > rn2(20))
1005 (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
1006 if((int) u.ulevel > rn2(25))
1007 (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
1008 if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg;
1009 if (mtmp->mhp <= 0) killed(mtmp);
1010 }
1011 /* For consistency with passive() in uhitm.c, this only
1012 * affects you if the monster is still alive.
1013 */
1014 if (!DEADMONSTER(mtmp) &&
1015 (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
1016 if (!Free_action) {
1017 You("are frozen by %s gaze!",
1018 s_suffix(mon_nam(mtmp)));
1019 nomul((u.ulevel > 6 || rn2(4)) ?
1020 -d((int)mtmp->m_lev+1,
1021 (int)mtmp->data->mattk[0].damd)
1022 : -200);
1023 return 1;
1024 } else
1025 You("stiffen momentarily under %s gaze.",
1026 s_suffix(mon_nam(mtmp)));
1027 }
1028 /* Technically this one shouldn't affect you at all because
1029 * the Medusa gaze is an active monster attack that only
1030 * works on the monster's turn, but for it to *not* have an
1031 * effect would be too weird.
1032 */
1033 if (!DEADMONSTER(mtmp) &&
1034 (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) {
1035 pline(
1036 "Gazing at the awake %s is not a very good idea.",
1037 l_monnam(mtmp));
1038 /* as if gazing at a sleeping anything is fruitful... */
1039 You("turn to stone...");
1040 killer_format = KILLED_BY;
1041 killer = "deliberately meeting Medusa's gaze";
1042 done(STONING);
1043 }
1044 }
1045 }
1046 }
1047 if (!looked) You("gaze at no place in particular.");
1048 return 1;
1049 }
1050
1051 int
dohide()1052 dohide()
1053 {
1054 boolean ismimic = youmonst.data->mlet == S_MIMIC;
1055
1056 if (u.uundetected || (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) {
1057 You("are already hiding.");
1058 return(0);
1059 }
1060 if (ismimic) {
1061 /* should bring up a dialog "what would you like to imitate?" */
1062 youmonst.m_ap_type = M_AP_OBJECT;
1063 youmonst.mappearance = STRANGE_OBJECT;
1064 } else
1065 u.uundetected = 1;
1066 newsym(u.ux,u.uy);
1067 return(1);
1068 }
1069
1070 int
domindblast()1071 domindblast()
1072 {
1073 struct monst *mtmp, *nmon;
1074
1075 if (u.uen < 10) {
1076 You("concentrate but lack the energy to maintain doing so.");
1077 return(0);
1078 }
1079 u.uen -= 10;
1080 flags.botl = 1;
1081
1082 You("concentrate.");
1083 pline("A wave of psychic energy pours out.");
1084 for(mtmp=fmon; mtmp; mtmp = nmon) {
1085 int u_sen;
1086
1087 nmon = mtmp->nmon;
1088 if (DEADMONSTER(mtmp))
1089 continue;
1090 if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM)
1091 continue;
1092 if(mtmp->mpeaceful)
1093 continue;
1094 u_sen = telepathic(mtmp->data) && !mtmp->mcansee;
1095 if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) {
1096 You("lock in on %s %s.", s_suffix(mon_nam(mtmp)),
1097 u_sen ? "telepathy" :
1098 telepathic(mtmp->data) ? "latent telepathy" :
1099 "mind");
1100 mtmp->mhp -= rnd(15);
1101 if (mtmp->mhp <= 0)
1102 killed(mtmp);
1103 }
1104 }
1105 return 1;
1106 }
1107
1108 STATIC_OVL void
uunstick()1109 uunstick()
1110 {
1111 pline("%s is no longer in your clutches.", Monnam(u.ustuck));
1112 u.ustuck = 0;
1113 }
1114
1115 void
skinback(silently)1116 skinback(silently)
1117 boolean silently;
1118 {
1119 if (uskin) {
1120 if (!silently) Your("skin returns to its original form.");
1121 uarm = uskin;
1122 uskin = (struct obj *)0;
1123 /* undo save/restore hack */
1124 uarm->owornmask &= ~I_SPECIAL;
1125 }
1126 }
1127
1128 #endif /* OVLB */
1129 #ifdef OVL1
1130
1131 const char *
mbodypart(mon,part)1132 mbodypart(mon, part)
1133 struct monst *mon;
1134 int part;
1135 {
1136 static NEARDATA const char
1137 *humanoid_parts[] = { "arm", "eye", "face", "finger",
1138 "fingertip", "foot", "hand", "handed", "head", "leg",
1139 "light headed", "neck", "spine", "toe", "hair",
1140 "blood", "lung", "nose", "stomach"},
1141 *jelly_parts[] = { "pseudopod", "dark spot", "front",
1142 "pseudopod extension", "pseudopod extremity",
1143 "pseudopod root", "grasp", "grasped", "cerebral area",
1144 "lower pseudopod", "viscous", "middle", "surface",
1145 "pseudopod extremity", "ripples", "juices",
1146 "surface", "sensor", "stomach" },
1147 *animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip",
1148 "rear claw", "foreclaw", "clawed", "head", "rear limb",
1149 "light headed", "neck", "spine", "rear claw tip",
1150 "fur", "blood", "lung", "nose", "stomach" },
1151 *bird_parts[] = { "wing", "eye", "face", "wing", "wing tip",
1152 "foot", "wing", "winged", "head", "leg",
1153 "light headed", "neck", "spine", "toe",
1154 "feathers", "blood", "lung", "bill", "stomach" },
1155 *horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip",
1156 "rear hoof", "foreclaw", "hooved", "head", "rear leg",
1157 "light headed", "neck", "backbone", "rear hoof tip",
1158 "mane", "blood", "lung", "nose", "stomach"},
1159 *sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle",
1160 "tentacle tip", "lower appendage", "tentacle", "tentacled",
1161 "body", "lower tentacle", "rotational", "equator", "body",
1162 "lower tentacle tip", "cilia", "life force", "retina",
1163 "olfactory nerve", "interior" },
1164 *fungus_parts[] = { "mycelium", "visual area", "front", "hypha",
1165 "hypha", "root", "strand", "stranded", "cap area",
1166 "rhizome", "sporulated", "stalk", "root", "rhizome tip",
1167 "spores", "juices", "gill", "gill", "interior" },
1168 *vortex_parts[] = { "region", "eye", "front", "minor current",
1169 "minor current", "lower current", "swirl", "swirled",
1170 "central core", "lower current", "addled", "center",
1171 "currents", "edge", "currents", "life force",
1172 "center", "leading edge", "interior" },
1173 *snake_parts[] = { "vestigial limb", "eye", "face", "large scale",
1174 "large scale tip", "rear region", "scale gap", "scale gapped",
1175 "head", "rear region", "light headed", "neck", "length",
1176 "rear scale", "scales", "blood", "lung", "forked tongue", "stomach" },
1177 *fish_parts[] = { "fin", "eye", "premaxillary", "pelvic axillary",
1178 "pelvic fin", "anal fin", "pectoral fin", "finned", "head", "peduncle",
1179 "played out", "gills", "dorsal fin", "caudal fin",
1180 "scales", "blood", "gill", "nostril", "stomach" };
1181 /* claw attacks are overloaded in mons[]; most humanoids with
1182 such attacks should still reference hands rather than claws */
1183 static const char not_claws[] = {
1184 S_HUMAN, S_MUMMY, S_ZOMBIE, S_ANGEL,
1185 S_NYMPH, S_LEPRECHAUN, S_QUANTMECH, S_VAMPIRE,
1186 S_ORC, S_GIANT, /* quest nemeses */
1187 '\0' /* string terminator; assert( S_xxx != 0 ); */
1188 };
1189 struct permonst *mptr = mon->data;
1190
1191 if (part == HAND || part == HANDED) { /* some special cases */
1192 if (mptr->mlet == S_DOG || mptr->mlet == S_FELINE ||
1193 mptr->mlet == S_YETI)
1194 return part == HAND ? "paw" : "pawed";
1195 if (humanoid(mptr) && attacktype(mptr, AT_CLAW) &&
1196 !index(not_claws, mptr->mlet) &&
1197 mptr != &mons[PM_STONE_GOLEM] &&
1198 mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS])
1199 return part == HAND ? "claw" : "clawed";
1200 }
1201 if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON]) &&
1202 part == NOSE)
1203 return "trunk";
1204 if (mptr == &mons[PM_SHARK] && part == HAIR)
1205 return "skin"; /* sharks don't have scales */
1206 if (mptr == &mons[PM_JELLYFISH] && (part == ARM || part == FINGER ||
1207 part == HAND || part == FOOT || part == TOE))
1208 return "tentacle";
1209 if (mptr == &mons[PM_FLOATING_EYE] && part == EYE)
1210 return "cornea";
1211 if (humanoid(mptr) &&
1212 (part == ARM || part == FINGER || part == FINGERTIP ||
1213 part == HAND || part == HANDED))
1214 return humanoid_parts[part];
1215 if (mptr == &mons[PM_RAVEN])
1216 return bird_parts[part];
1217 if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN ||
1218 (mptr == &mons[PM_ROTHE] && part != HAIR))
1219 return horse_parts[part];
1220 if (mptr->mlet == S_LIGHT) {
1221 if (part == HANDED) return "rayed";
1222 else if (part == ARM || part == FINGER ||
1223 part == FINGERTIP || part == HAND) return "ray";
1224 else return "beam";
1225 }
1226 if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH])
1227 return fish_parts[part];
1228 if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR))
1229 return snake_parts[part];
1230 if (mptr->mlet == S_EYE)
1231 return sphere_parts[part];
1232 if (mptr->mlet == S_JELLY || mptr->mlet == S_PUDDING ||
1233 mptr->mlet == S_BLOB || mptr == &mons[PM_JELLYFISH])
1234 return jelly_parts[part];
1235 if (mptr->mlet == S_VORTEX || mptr->mlet == S_ELEMENTAL)
1236 return vortex_parts[part];
1237 if (mptr->mlet == S_FUNGUS)
1238 return fungus_parts[part];
1239 if (humanoid(mptr))
1240 return humanoid_parts[part];
1241 return animal_parts[part];
1242 }
1243
1244 const char *
body_part(part)1245 body_part(part)
1246 int part;
1247 {
1248 return mbodypart(&youmonst, part);
1249 }
1250
1251 #endif /* OVL1 */
1252 #ifdef OVL0
1253
1254 int
poly_gender()1255 poly_gender()
1256 {
1257 /* Returns gender of polymorphed player; 0/1=same meaning as flags.female,
1258 * 2=none.
1259 */
1260 if (is_neuter(youmonst.data) || !humanoid(youmonst.data)) return 2;
1261 return flags.female;
1262 }
1263
1264 #endif /* OVL0 */
1265 #ifdef OVLB
1266
1267 void
ugolemeffects(damtype,dam)1268 ugolemeffects(damtype, dam)
1269 int damtype, dam;
1270 {
1271 int heal = 0;
1272 /* We won't bother with "slow"/"haste" since players do not
1273 * have a monster-specific slow/haste so there is no way to
1274 * restore the old velocity once they are back to human.
1275 */
1276 if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM)
1277 return;
1278 switch (damtype) {
1279 case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM)
1280 heal = dam / 6; /* Approx 1 per die */
1281 break;
1282 case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM)
1283 heal = dam;
1284 break;
1285 }
1286 if (heal && (u.mh < u.mhmax)) {
1287 u.mh += heal;
1288 if (u.mh > u.mhmax) u.mh = u.mhmax;
1289 flags.botl = 1;
1290 pline("Strangely, you feel better than before.");
1291 exercise(A_STR, TRUE);
1292 }
1293 }
1294
1295 STATIC_OVL int
armor_to_dragon(atyp)1296 armor_to_dragon(atyp)
1297 int atyp;
1298 {
1299 switch(atyp) {
1300 case GRAY_DRAGON_SCALE_MAIL:
1301 case GRAY_DRAGON_SCALES:
1302 return PM_GRAY_DRAGON;
1303 case SILVER_DRAGON_SCALE_MAIL:
1304 case SILVER_DRAGON_SCALES:
1305 return PM_SILVER_DRAGON;
1306 #if 0 /* DEFERRED */
1307 case SHIMMERING_DRAGON_SCALE_MAIL:
1308 case SHIMMERING_DRAGON_SCALES:
1309 return PM_SHIMMERING_DRAGON;
1310 #endif
1311 case RED_DRAGON_SCALE_MAIL:
1312 case RED_DRAGON_SCALES:
1313 return PM_RED_DRAGON;
1314 case ORANGE_DRAGON_SCALE_MAIL:
1315 case ORANGE_DRAGON_SCALES:
1316 return PM_ORANGE_DRAGON;
1317 case WHITE_DRAGON_SCALE_MAIL:
1318 case WHITE_DRAGON_SCALES:
1319 return PM_WHITE_DRAGON;
1320 case BLACK_DRAGON_SCALE_MAIL:
1321 case BLACK_DRAGON_SCALES:
1322 return PM_BLACK_DRAGON;
1323 case BLUE_DRAGON_SCALE_MAIL:
1324 case BLUE_DRAGON_SCALES:
1325 return PM_BLUE_DRAGON;
1326 case GREEN_DRAGON_SCALE_MAIL:
1327 case GREEN_DRAGON_SCALES:
1328 return PM_GREEN_DRAGON;
1329 case YELLOW_DRAGON_SCALE_MAIL:
1330 case YELLOW_DRAGON_SCALES:
1331 return PM_YELLOW_DRAGON;
1332 default:
1333 return -1;
1334 }
1335 }
1336
1337 #endif /* OVLB */
1338
1339 /*polyself.c*/
1340