1/*	SCCS Id: @(#)mondata.c	3.4	2003/06/02	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5#include "hack.h"
6#include "eshk.h"
7#include "epri.h"
8
9/*	These routines provide basic data for any type of monster. */
10
11#ifdef OVLB
12
13void
14set_mon_data(mon, ptr, flag)
15struct monst *mon;
16struct permonst *ptr;
17int flag;
18{
19    mon->data = ptr;
20    if (flag == -1) return;		/* "don't care" */
21
22    if (flag == 1)
23	mon->mintrinsics |= (ptr->mresists & 0x00FF);
24    else
25	mon->mintrinsics = (ptr->mresists & 0x00FF);
26    return;
27}
28
29#endif /* OVLB */
30#ifdef OVL0
31
32struct attack *
33attacktype_fordmg(ptr, atyp, dtyp)
34struct permonst *ptr;
35int atyp, dtyp;
36{
37    struct attack *a;
38
39    for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++)
40	if (a->aatyp == atyp && (dtyp == AD_ANY || a->adtyp == dtyp))
41	    return a;
42
43    return (struct attack *)0;
44}
45
46boolean
47attacktype(ptr, atyp)
48struct permonst *ptr;
49int atyp;
50{
51    return attacktype_fordmg(ptr, atyp, AD_ANY) ? TRUE : FALSE;
52}
53
54#endif /* OVL0 */
55#ifdef OVLB
56
57boolean
58poly_when_stoned(ptr)
59    struct permonst *ptr;
60{
61    return((boolean)(is_golem(ptr) && ptr != &mons[PM_STONE_GOLEM] &&
62	    !(mvitals[PM_STONE_GOLEM].mvflags & G_GENOD)));
63	    /* allow G_EXTINCT */
64}
65
66boolean
67resists_drli(mon)	/* returns TRUE if monster is drain-life resistant */
68struct monst *mon;
69{
70	struct permonst *ptr = mon->data;
71	struct obj *wep = ((mon == &youmonst) ? uwep : MON_WEP(mon));
72
73	return (boolean)(is_undead(ptr) || is_demon(ptr) || is_were(ptr) ||
74			 ptr == &mons[PM_DEATH] ||
75			 (wep && wep->oartifact && defends(AD_DRLI, wep)));
76}
77
78boolean
79resists_magm(mon)	/* TRUE if monster is magic-missile resistant */
80struct monst *mon;
81{
82	struct permonst *ptr = mon->data;
83	struct obj *o;
84
85	/* as of 3.2.0:  gray dragons, Angels, Oracle, Yeenoghu */
86	if (dmgtype(ptr, AD_MAGM) || ptr == &mons[PM_BABY_GRAY_DRAGON] ||
87		dmgtype(ptr, AD_RBRE))	/* Chromatic Dragon */
88	    return TRUE;
89	/* check for magic resistance granted by wielded weapon */
90	o = (mon == &youmonst) ? uwep : MON_WEP(mon);
91	if (o && o->oartifact && defends(AD_MAGM, o))
92	    return TRUE;
93	/* check for magic resistance granted by worn or carried items */
94	o = (mon == &youmonst) ? invent : mon->minvent;
95	for ( ; o; o = o->nobj)
96	    if ((o->owornmask && objects[o->otyp].oc_oprop == ANTIMAGIC) ||
97		    (o->oartifact && protects(AD_MAGM, o)))
98		return TRUE;
99	return FALSE;
100}
101
102/* TRUE iff monster is resistant to light-induced blindness */
103boolean
104resists_blnd(mon)
105struct monst *mon;
106{
107	struct permonst *ptr = mon->data;
108	boolean is_you = (mon == &youmonst);
109	struct obj *o;
110
111	if (is_you ? (Blind || u.usleep) :
112		(mon->mblinded || !mon->mcansee || !haseyes(ptr) ||
113		    /* BUG: temporary sleep sets mfrozen, but since
114			    paralysis does too, we can't check it */
115		    mon->msleeping))
116	    return TRUE;
117	/* yellow light, Archon; !dust vortex, !cobra, !raven */
118	if (dmgtype_fromattack(ptr, AD_BLND, AT_EXPL) ||
119		dmgtype_fromattack(ptr, AD_BLND, AT_GAZE))
120	    return TRUE;
121	o = is_you ? uwep : MON_WEP(mon);
122	if (o && o->oartifact && defends(AD_BLND, o))
123	    return TRUE;
124	o = is_you ? invent : mon->minvent;
125	for ( ; o; o = o->nobj)
126	    if ((o->owornmask && objects[o->otyp].oc_oprop == BLINDED) ||
127		    (o->oartifact && protects(AD_BLND, o)))
128		return TRUE;
129	return FALSE;
130}
131
132/* TRUE iff monster can be blinded by the given attack */
133/* Note: may return TRUE when mdef is blind (e.g. new cream-pie attack) */
134boolean
135can_blnd(magr, mdef, aatyp, obj)
136struct monst *magr;		/* NULL == no specific aggressor */
137struct monst *mdef;
138uchar aatyp;
139struct obj *obj;		/* aatyp == AT_WEAP, AT_SPIT */
140{
141	boolean is_you = (mdef == &youmonst);
142	boolean check_visor = FALSE;
143	struct obj *o;
144	const char *s;
145
146	/* no eyes protect against all attacks for now */
147	if (!haseyes(mdef->data))
148	    return FALSE;
149
150	switch(aatyp) {
151	case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_MAGC:
152	case AT_BREA: /* assumed to be lightning */
153	    /* light-based attacks may be cancelled or resisted */
154	    if (magr && magr->mcan)
155		return FALSE;
156	    return !resists_blnd(mdef);
157
158	case AT_WEAP: case AT_SPIT: case AT_NONE:
159	    /* an object is used (thrown/spit/other) */
160	    if (obj && (obj->otyp == CREAM_PIE)) {
161		if (is_you && Blindfolded)
162		    return FALSE;
163	    } else if (obj && (obj->otyp == BLINDING_VENOM)) {
164		/* all ublindf, including LENSES, protect, cream-pies too */
165		if (is_you && (ublindf || u.ucreamed))
166		    return FALSE;
167		check_visor = TRUE;
168	    } else if (obj && (obj->otyp == POT_BLINDNESS)) {
169		return TRUE;	/* no defense */
170	    } else
171		return FALSE;	/* other objects cannot cause blindness yet */
172	    if ((magr == &youmonst) && u.uswallow)
173		return FALSE;	/* can't affect eyes while inside monster */
174	    break;
175
176	case AT_ENGL:
177	    if (is_you && (Blindfolded || u.usleep || u.ucreamed))
178		return FALSE;
179	    if (!is_you && mdef->msleeping)
180		return FALSE;
181	    break;
182
183	case AT_CLAW:
184	    /* e.g. raven: all ublindf, including LENSES, protect */
185	    if (is_you && ublindf)
186		return FALSE;
187	    if ((magr == &youmonst) && u.uswallow)
188		return FALSE;	/* can't affect eyes while inside monster */
189	    check_visor = TRUE;
190	    break;
191
192	case AT_TUCH: case AT_STNG:
193	    /* some physical, blind-inducing attacks can be cancelled */
194	    if (magr && magr->mcan)
195		return FALSE;
196	    break;
197
198	default:
199	    break;
200	}
201
202	/* check if wearing a visor (only checked if visor might help) */
203	if (check_visor) {
204	    o = (mdef == &youmonst) ? invent : mdef->minvent;
205	    for ( ; o; o = o->nobj)
206		if ((o->owornmask & W_ARMH) &&
207		    (s = OBJ_DESCR(objects[o->otyp])) != (char *)0 &&
208		    !strcmp(s, "visored helmet"))
209		    return FALSE;
210	}
211
212	return TRUE;
213}
214
215#endif /* OVLB */
216#ifdef OVL0
217
218boolean
219ranged_attk(ptr)	/* returns TRUE if monster can attack at range */
220struct permonst *ptr;
221{
222	register int i, atyp;
223	long atk_mask = (1L << AT_BREA) | (1L << AT_SPIT) | (1L << AT_GAZE);
224
225	/* was: (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) ||
226		attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) ||
227		attacktype(ptr, AT_MAGC));
228	   but that's too slow -dlc
229	 */
230	for (i = 0; i < NATTK; i++) {
231	    atyp = ptr->mattk[i].aatyp;
232	    if (atyp >= AT_WEAP) return TRUE;
233	 /* assert(atyp < 32); */
234	    if ((atk_mask & (1L << atyp)) != 0L) return TRUE;
235	}
236
237	return FALSE;
238}
239
240boolean
241hates_silver(ptr)
242register struct permonst *ptr;
243/* returns TRUE if monster is especially affected by silver weapons */
244{
245	return((boolean)(is_were(ptr) || ptr->mlet==S_VAMPIRE || is_demon(ptr) ||
246		ptr == &mons[PM_SHADE] ||
247		(ptr->mlet==S_IMP && ptr != &mons[PM_TENGU])));
248}
249
250/* true iff the type of monster pass through iron bars */
251boolean
252passes_bars(mptr)
253struct permonst *mptr;
254{
255    return (boolean) (passes_walls(mptr) || amorphous(mptr) ||
256		      is_whirly(mptr) || verysmall(mptr) ||
257		      (slithy(mptr) && !bigmonst(mptr)));
258}
259
260#endif /* OVL0 */
261#ifdef OVL1
262
263boolean
264can_track(ptr)		/* returns TRUE if monster can track well */
265	register struct permonst *ptr;
266{
267	if (uwep && uwep->oartifact == ART_EXCALIBUR)
268		return TRUE;
269	else
270		return((boolean)haseyes(ptr));
271}
272
273#endif /* OVL1 */
274#ifdef OVLB
275
276boolean
277sliparm(ptr)	/* creature will slide out of armor */
278	register struct permonst *ptr;
279{
280	return((boolean)(is_whirly(ptr) || ptr->msize <= MZ_SMALL ||
281			 noncorporeal(ptr)));
282}
283
284boolean
285breakarm(ptr)	/* creature will break out of armor */
286	register struct permonst *ptr;
287{
288	return ((bigmonst(ptr) || (ptr->msize > MZ_SMALL && !humanoid(ptr)) ||
289		/* special cases of humanoids that cannot wear body armor */
290		ptr == &mons[PM_MARILITH] || ptr == &mons[PM_WINGED_GARGOYLE])
291	      && !sliparm(ptr));
292}
293#endif /* OVLB */
294#ifdef OVL1
295
296boolean
297sticks(ptr)	/* creature sticks other creatures it hits */
298	register struct permonst *ptr;
299{
300	return((boolean)(dmgtype(ptr,AD_STCK) || dmgtype(ptr,AD_WRAP) ||
301		attacktype(ptr,AT_HUGS)));
302}
303
304/* number of horns this type of monster has on its head */
305int
306num_horns(ptr)
307struct permonst *ptr;
308{
309    switch (monsndx(ptr)) {
310    case PM_HORNED_DEVIL:	/* ? "more than one" */
311    case PM_MINOTAUR:
312    case PM_ASMODEUS:
313    case PM_BALROG:
314	return 2;
315    case PM_WHITE_UNICORN:
316    case PM_GRAY_UNICORN:
317    case PM_BLACK_UNICORN:
318    case PM_KI_RIN:
319	return 1;
320    default:
321	break;
322    }
323    return 0;
324}
325
326struct attack *
327dmgtype_fromattack(ptr, dtyp, atyp)
328struct permonst *ptr;
329int dtyp, atyp;
330{
331    struct attack *a;
332
333    for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++)
334	if (a->adtyp == dtyp && (atyp == AT_ANY || a->aatyp == atyp))
335	    return a;
336
337    return (struct attack *)0;
338}
339
340boolean
341dmgtype(ptr, dtyp)
342struct permonst *ptr;
343int dtyp;
344{
345    return dmgtype_fromattack(ptr, dtyp, AT_ANY) ? TRUE : FALSE;
346}
347
348/* returns the maximum damage a defender can do to the attacker via
349 * a passive defense */
350int
351max_passive_dmg(mdef, magr)
352    register struct monst *mdef, *magr;
353{
354    int	i, dmg = 0;
355    uchar adtyp;
356
357    for(i = 0; i < NATTK; i++)
358	if(mdef->data->mattk[i].aatyp == AT_NONE ||
359		mdef->data->mattk[i].aatyp == AT_BOOM) {
360	    adtyp = mdef->data->mattk[i].adtyp;
361	    if ((adtyp == AD_ACID && !resists_acid(magr)) ||
362		    (adtyp == AD_COLD && !resists_cold(magr)) ||
363		    (adtyp == AD_FIRE && !resists_fire(magr)) ||
364		    (adtyp == AD_ELEC && !resists_elec(magr)) ||
365		    adtyp == AD_PHYS) {
366		dmg = mdef->data->mattk[i].damn;
367		if(!dmg) dmg = mdef->data->mlevel+1;
368		dmg *= mdef->data->mattk[i].damd;
369	    } else dmg = 0;
370
371	    return dmg;
372	}
373    return 0;
374}
375
376#endif /* OVL1 */
377#ifdef OVL0
378
379int
380monsndx(ptr)		/* return an index into the mons array */
381	struct	permonst	*ptr;
382{
383	register int	i;
384
385	i = (int)(ptr - &mons[0]);
386	if (i < LOW_PM || i >= NUMMONS) {
387		/* ought to switch this to use `fmt_ptr' */
388	    panic("monsndx - could not index monster (%lx)",
389		  (unsigned long)ptr);
390	    return NON_PM;		/* will not get here */
391	}
392
393	return(i);
394}
395
396#endif /* OVL0 */
397#ifdef OVL1
398
399
400int
401name_to_mon(in_str)
402const char *in_str;
403{
404	/* Be careful.  We must check the entire string in case it was
405	 * something such as "ettin zombie corpse".  The calling routine
406	 * doesn't know about the "corpse" until the monster name has
407	 * already been taken off the front, so we have to be able to
408	 * read the name with extraneous stuff such as "corpse" stuck on
409	 * the end.
410	 * This causes a problem for names which prefix other names such
411	 * as "ettin" on "ettin zombie".  In this case we want the _longest_
412	 * name which exists.
413	 * This also permits plurals created by adding suffixes such as 's'
414	 * or 'es'.  Other plurals must still be handled explicitly.
415	 */
416	register int i;
417	register int mntmp = NON_PM;
418	register char *s, *str, *term;
419	char buf[BUFSZ];
420	int len, slen;
421
422	str = strcpy(buf, in_str);
423
424	if (!strncmp(str, "a ", 2)) str += 2;
425	else if (!strncmp(str, "an ", 3)) str += 3;
426
427	slen = strlen(str);
428	term = str + slen;
429
430	if ((s = strstri(str, "vortices")) != 0)
431	    Strcpy(s+4, "ex");
432	/* be careful with "ies"; "priest", "zombies" */
433	else if (slen > 3 && !strcmpi(term-3, "ies") &&
434		    (slen < 7 || strcmpi(term-7, "zombies")))
435	    Strcpy(term-3, "y");
436	/* luckily no monster names end in fe or ve with ves plurals */
437	else if (slen > 3 && !strcmpi(term-3, "ves"))
438	    Strcpy(term-3, "f");
439
440	slen = strlen(str); /* length possibly needs recomputing */
441
442    {
443	static const struct alt_spl { const char* name; short pm_val; }
444	    names[] = {
445	    /* Alternate spellings */
446		{ "grey dragon",	PM_GRAY_DRAGON },
447		{ "baby grey dragon",	PM_BABY_GRAY_DRAGON },
448		{ "grey unicorn",	PM_GRAY_UNICORN },
449		{ "grey ooze",		PM_GRAY_OOZE },
450		{ "gray-elf",		PM_GREY_ELF },
451	    /* Hyphenated names */
452		{ "ki rin",		PM_KI_RIN },
453		{ "uruk hai",		PM_URUK_HAI },
454		{ "orc captain",	PM_ORC_CAPTAIN },
455		{ "woodland elf",	PM_WOODLAND_ELF },
456		{ "green elf",		PM_GREEN_ELF },
457		{ "grey elf",		PM_GREY_ELF },
458		{ "gray elf",		PM_GREY_ELF },
459		{ "elf lord",		PM_ELF_LORD },
460#if 0	/* OBSOLETE */
461		{ "high elf",		PM_HIGH_ELF },
462#endif
463		{ "olog hai",		PM_OLOG_HAI },
464		{ "arch lich",		PM_ARCH_LICH },
465	    /* Some irregular plurals */
466		{ "incubi",		PM_INCUBUS },
467		{ "succubi",		PM_SUCCUBUS },
468		{ "violet fungi",	PM_VIOLET_FUNGUS },
469		{ "homunculi",		PM_HOMUNCULUS },
470		{ "baluchitheria",	PM_BALUCHITHERIUM },
471		{ "lurkers above",	PM_LURKER_ABOVE },
472		{ "cavemen",		PM_CAVEMAN },
473		{ "cavewomen",		PM_CAVEWOMAN },
474		{ "djinn",		PM_DJINNI },
475		{ "mumakil",		PM_MUMAK },
476		{ "erinyes",		PM_ERINYS },
477	    /* falsely caught by -ves check above */
478		{ "master of thief",	PM_MASTER_OF_THIEVES },
479	    /* end of list */
480		{ 0, 0 }
481	};
482	register const struct alt_spl *namep;
483
484	for (namep = names; namep->name; namep++)
485	    if (!strncmpi(str, namep->name, (int)strlen(namep->name)))
486		return namep->pm_val;
487    }
488
489	for (len = 0, i = LOW_PM; i < NUMMONS; i++) {
490	    register int m_i_len = strlen(mons[i].mname);
491	    if (m_i_len > len && !strncmpi(mons[i].mname, str, m_i_len)) {
492		if (m_i_len == slen) return i;	/* exact match */
493		else if (slen > m_i_len &&
494			(str[m_i_len] == ' ' ||
495			 !strcmpi(&str[m_i_len], "s") ||
496			 !strncmpi(&str[m_i_len], "s ", 2) ||
497			 !strcmpi(&str[m_i_len], "'") ||
498			 !strncmpi(&str[m_i_len], "' ", 2) ||
499			 !strcmpi(&str[m_i_len], "'s") ||
500			 !strncmpi(&str[m_i_len], "'s ", 3) ||
501			 !strcmpi(&str[m_i_len], "es") ||
502			 !strncmpi(&str[m_i_len], "es ", 3))) {
503		    mntmp = i;
504		    len = m_i_len;
505		}
506	    }
507	}
508	if (mntmp == NON_PM) mntmp = title_to_mon(str, (int *)0, (int *)0);
509	return mntmp;
510}
511
512#endif /* OVL1 */
513#ifdef OVL2
514
515/* returns 3 values (0=male, 1=female, 2=none) */
516int
517gender(mtmp)
518register struct monst *mtmp;
519{
520	if (is_neuter(mtmp->data)) return 2;
521	return mtmp->female;
522}
523
524/* Like gender(), but lower animals and such are still "it". */
525/* This is the one we want to use when printing messages. */
526int
527pronoun_gender(mtmp)
528register struct monst *mtmp;
529{
530	if (is_neuter(mtmp->data) || !canspotmon(mtmp)) return 2;
531	return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) ||
532		type_is_pname(mtmp->data)) ? (int)mtmp->female : 2;
533}
534
535#endif /* OVL2 */
536#ifdef OVLB
537
538/* used for nearby monsters when you go to another level */
539boolean
540levl_follower(mtmp)
541struct monst *mtmp;
542{
543	/* monsters with the Amulet--even pets--won't follow across levels */
544	if (mon_has_amulet(mtmp)) return FALSE;
545
546	/* some monsters will follow even while intending to flee from you */
547	if (mtmp->mtame || mtmp->iswiz || is_fshk(mtmp)) return TRUE;
548
549	/* stalking types follow, but won't when fleeing unless you hold
550	   the Amulet */
551	return (boolean)((mtmp->data->mflags2 & M2_STALK) &&
552				(!mtmp->mflee || u.uhave.amulet));
553}
554
555static const short grownups[][2] = {
556	{PM_CHICKATRICE, PM_COCKATRICE},
557	{PM_LITTLE_DOG, PM_DOG}, {PM_DOG, PM_LARGE_DOG},
558	{PM_HELL_HOUND_PUP, PM_HELL_HOUND},
559	{PM_WINTER_WOLF_CUB, PM_WINTER_WOLF},
560	{PM_KITTEN, PM_HOUSECAT}, {PM_HOUSECAT, PM_LARGE_CAT},
561	{PM_PONY, PM_HORSE}, {PM_HORSE, PM_WARHORSE},
562	{PM_KOBOLD, PM_LARGE_KOBOLD}, {PM_LARGE_KOBOLD, PM_KOBOLD_LORD},
563	{PM_GNOME, PM_GNOME_LORD}, {PM_GNOME_LORD, PM_GNOME_KING},
564	{PM_DWARF, PM_DWARF_LORD}, {PM_DWARF_LORD, PM_DWARF_KING},
565	{PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER},
566	{PM_ORC, PM_ORC_CAPTAIN}, {PM_HILL_ORC, PM_ORC_CAPTAIN},
567	{PM_MORDOR_ORC, PM_ORC_CAPTAIN}, {PM_URUK_HAI, PM_ORC_CAPTAIN},
568	{PM_SEWER_RAT, PM_GIANT_RAT},
569	{PM_CAVE_SPIDER, PM_GIANT_SPIDER},
570	{PM_OGRE, PM_OGRE_LORD}, {PM_OGRE_LORD, PM_OGRE_KING},
571	{PM_ELF, PM_ELF_LORD}, {PM_WOODLAND_ELF, PM_ELF_LORD},
572	{PM_GREEN_ELF, PM_ELF_LORD}, {PM_GREY_ELF, PM_ELF_LORD},
573	{PM_ELF_LORD, PM_ELVENKING},
574	{PM_LICH, PM_DEMILICH}, {PM_DEMILICH, PM_MASTER_LICH},
575	{PM_MASTER_LICH, PM_ARCH_LICH},
576	{PM_VAMPIRE, PM_VAMPIRE_LORD}, {PM_BAT, PM_GIANT_BAT},
577	{PM_BABY_GRAY_DRAGON, PM_GRAY_DRAGON},
578	{PM_BABY_SILVER_DRAGON, PM_SILVER_DRAGON},
579#if 0	/* DEFERRED */
580	{PM_BABY_SHIMMERING_DRAGON, PM_SHIMMERING_DRAGON},
581#endif
582	{PM_BABY_RED_DRAGON, PM_RED_DRAGON},
583	{PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON},
584	{PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON},
585	{PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON},
586	{PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON},
587	{PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON},
588	{PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON},
589	{PM_RED_NAGA_HATCHLING, PM_RED_NAGA},
590	{PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA},
591	{PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA},
592	{PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA},
593	{PM_SMALL_MIMIC, PM_LARGE_MIMIC}, {PM_LARGE_MIMIC, PM_GIANT_MIMIC},
594	{PM_BABY_LONG_WORM, PM_LONG_WORM},
595	{PM_BABY_PURPLE_WORM, PM_PURPLE_WORM},
596	{PM_BABY_CROCODILE, PM_CROCODILE},
597	{PM_SOLDIER, PM_SERGEANT},
598	{PM_SERGEANT, PM_LIEUTENANT},
599	{PM_LIEUTENANT, PM_CAPTAIN},
600	{PM_WATCHMAN, PM_WATCH_CAPTAIN},
601	{PM_ALIGNED_PRIEST, PM_HIGH_PRIEST},
602	{PM_STUDENT, PM_ARCHEOLOGIST},
603	{PM_ATTENDANT, PM_HEALER},
604	{PM_PAGE, PM_KNIGHT},
605	{PM_ACOLYTE, PM_PRIEST},
606	{PM_APPRENTICE, PM_WIZARD},
607	{PM_MANES,PM_LEMURE},
608#ifdef KOPS
609	{PM_KEYSTONE_KOP, PM_KOP_SERGEANT},
610	{PM_KOP_SERGEANT, PM_KOP_LIEUTENANT},
611	{PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN},
612#endif
613	{NON_PM,NON_PM}
614};
615
616int
617little_to_big(montype)
618int montype;
619{
620#ifndef AIXPS2_BUG
621	register int i;
622
623	for (i = 0; grownups[i][0] >= LOW_PM; i++)
624		if(montype == grownups[i][0]) return grownups[i][1];
625	return montype;
626#else
627/* AIX PS/2 C-compiler 1.1.1 optimizer does not like the above for loop,
628 * and causes segmentation faults at runtime.  (The problem does not
629 * occur if -O is not used.)
630 * lehtonen@cs.Helsinki.FI (Tapio Lehtonen) 28031990
631 */
632	int i;
633	int monvalue;
634
635	monvalue = montype;
636	for (i = 0; grownups[i][0] >= LOW_PM; i++)
637		if(montype == grownups[i][0]) monvalue = grownups[i][1];
638
639	return monvalue;
640#endif
641}
642
643int
644big_to_little(montype)
645int montype;
646{
647	register int i;
648
649	for (i = 0; grownups[i][0] >= LOW_PM; i++)
650		if(montype == grownups[i][1]) return grownups[i][0];
651	return montype;
652}
653
654/*
655 * Return the permonst ptr for the race of the monster.
656 * Returns correct pointer for non-polymorphed and polymorphed
657 * player.  It does not return a pointer to player role character.
658 */
659const struct permonst *
660raceptr(mtmp)
661struct monst *mtmp;
662{
663    if (mtmp == &youmonst && !Upolyd) return(&mons[urace.malenum]);
664    else return(mtmp->data);
665}
666
667static const char *levitate[4]	= { "float", "Float", "wobble", "Wobble" };
668static const char *flys[4]	= { "fly", "Fly", "flutter", "Flutter" };
669static const char *flyl[4]	= { "fly", "Fly", "stagger", "Stagger" };
670static const char *slither[4]	= { "slither", "Slither", "falter", "Falter" };
671static const char *ooze[4]	= { "ooze", "Ooze", "tremble", "Tremble" };
672static const char *immobile[4]	= { "wiggle", "Wiggle", "pulsate", "Pulsate" };
673static const char *crawl[4]	= { "crawl", "Crawl", "falter", "Falter" };
674
675const char *
676locomotion(ptr, def)
677const struct permonst *ptr;
678const char *def;
679{
680	int capitalize = (*def == highc(*def));
681
682	return (
683		is_floater(ptr) ? levitate[capitalize] :
684		(is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] :
685		(is_flyer(ptr) && ptr->msize > MZ_SMALL)  ? flyl[capitalize] :
686		slithy(ptr)     ? slither[capitalize] :
687		amorphous(ptr)  ? ooze[capitalize] :
688		!ptr->mmove	? immobile[capitalize] :
689		nolimbs(ptr)    ? crawl[capitalize] :
690		def
691	       );
692
693}
694
695const char *
696stagger(ptr, def)
697const struct permonst *ptr;
698const char *def;
699{
700	int capitalize = 2 + (*def == highc(*def));
701
702	return (
703		is_floater(ptr) ? levitate[capitalize] :
704		(is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] :
705		(is_flyer(ptr) && ptr->msize > MZ_SMALL)  ? flyl[capitalize] :
706		slithy(ptr)     ? slither[capitalize] :
707		amorphous(ptr)  ? ooze[capitalize] :
708		!ptr->mmove	? immobile[capitalize] :
709		nolimbs(ptr)    ? crawl[capitalize] :
710		def
711	       );
712
713}
714
715/* return a phrase describing the effect of fire attack on a type of monster */
716const char *
717on_fire(mptr, mattk)
718struct permonst *mptr;
719struct attack *mattk;
720{
721    const char *what;
722
723    switch (monsndx(mptr)) {
724    case PM_FLAMING_SPHERE:
725    case PM_FIRE_VORTEX:
726    case PM_FIRE_ELEMENTAL:
727    case PM_SALAMANDER:
728	what = "already on fire";
729	break;
730    case PM_WATER_ELEMENTAL:
731    case PM_FOG_CLOUD:
732    case PM_STEAM_VORTEX:
733	what = "boiling";
734	break;
735    case PM_ICE_VORTEX:
736    case PM_GLASS_GOLEM:
737	what = "melting";
738	break;
739    case PM_STONE_GOLEM:
740    case PM_CLAY_GOLEM:
741    case PM_GOLD_GOLEM:
742    case PM_AIR_ELEMENTAL:
743    case PM_EARTH_ELEMENTAL:
744    case PM_DUST_VORTEX:
745    case PM_ENERGY_VORTEX:
746	what = "heating up";
747	break;
748    default:
749	what = (mattk->aatyp == AT_HUGS) ? "being roasted" : "on fire";
750	break;
751    }
752    return what;
753}
754
755#endif /* OVLB */
756
757/*mondata.c*/
758