/*	SCCS Id: @(#)makemon.c	3.1	92/11/01	*/
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"
#include "epri.h"
#include "emin.h"
#ifdef REINCARNATION
# include <ctype.h>
#endif

STATIC_VAR struct monst NEARDATA zeromonst;

#define uncommon(ptr) \
	(((ptr)->geno & (G_GENOD | G_EXTINCT | G_NOGEN | G_UNIQ)) || \
	 (!Inhell ? ((ptr)->geno & G_HELL) : ((ptr)->maligntyp > A_NEUTRAL)))

#ifdef OVL0
static boolean NDECL(cmavail);
static int FDECL(align_shift, (struct permonst *));
#endif /* OVL0 */
STATIC_DCL boolean FDECL(is_home_elemental,(struct permonst *));
STATIC_DCL boolean FDECL(wrong_elem_type, (struct permonst *));
STATIC_DCL void FDECL(m_initgrp,(struct monst *,int,int,int));
STATIC_DCL void FDECL(m_initthrow,(struct monst *,int,int));
STATIC_DCL void FDECL(m_initweap,(struct monst *));
#ifdef OVL1
static void FDECL(m_initinv,(struct monst *));
#endif /* OVL1 */

extern int monstr[];

#define m_initsgrp(mtmp, x, y)	m_initgrp(mtmp, x, y, 3)
#define m_initlgrp(mtmp, x, y)	m_initgrp(mtmp, x, y, 10)
#define toostrong(monindx, lev) (monstr[monindx] > lev)
#define tooweak(monindx, lev)	(monstr[monindx] < lev)

#ifdef OVLB
STATIC_OVL boolean
is_home_elemental(ptr)
register struct permonst *ptr;
{
	if (ptr->mlet != S_ELEMENTAL) return FALSE;
	if (!In_endgame(&u.uz)) return FALSE;
	switch(monsndx(ptr)) {
		case PM_AIR_ELEMENTAL: return Is_airlevel(&u.uz);
		case PM_FIRE_ELEMENTAL: return Is_firelevel(&u.uz);
		case PM_EARTH_ELEMENTAL: return Is_earthlevel(&u.uz);
		case PM_WATER_ELEMENTAL: return Is_waterlevel(&u.uz);
	}
	return FALSE;	/* shouldn't be reached */
}

/*
 * Return true if the given monster cannot exist on this elemental level.
 */
STATIC_OVL boolean
wrong_elem_type(ptr)
    register struct permonst *ptr;
{
    if (Is_earthlevel(&u.uz)) {
	/* no restrictions? */
    } else if (Is_waterlevel(&u.uz)) {
	/* just monsters that can swim */
	if(!is_swimmer(ptr)) return TRUE;
    } else if (Is_firelevel(&u.uz)) {
	if(!resists_fire(ptr)) return TRUE;
    } else if (Is_airlevel(&u.uz)) {
	if(!(is_flyer(ptr) && ptr->mlet != S_TRAPPER) && !is_floater(ptr)
	   && !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr))
	    return TRUE;
    }
    return FALSE;
}

STATIC_OVL void
m_initgrp(mtmp, x, y, n)	/* make a group just like mtmp */
register struct monst *mtmp;
register int x, y, n;
{
	coord mm;
	register int cnt = rnd(n);
	struct monst *mon;

/*
 *	Temporary kludge to cut down on swarming at lower character levels
 *	till we can get this game a little more balanced. [mrs]
 */
	cnt /= (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1;
	if(!cnt) cnt++;

	mm.x = x;
	mm.y = y;
	while(cnt--) {
		if (peace_minded(mtmp->data)) continue;
		/* Don't create groups of peaceful monsters since they'll get
		 * in our way.  If the monster has a percentage chance so some
		 * are peaceful and some are not, the result will just be a
		 * smaller group.
		 */
		if (enexto(&mm, mm.x, mm.y, mtmp->data)) {
		    mon = makemon(mtmp->data, mm.x, mm.y);
		    mon->mpeaceful = FALSE;
		    set_malign(mon);
		    /* Undo the second peace_minded() check in makemon(); if the
		     * monster turned out to be peaceful the first time we
		     * didn't create it at all; we don't want a second check.
		     */
		}
	}
}

STATIC_OVL
void
m_initthrow(mtmp,otyp,oquan)
struct monst *mtmp;
int otyp,oquan;
{
	register struct obj *otmp;

	otmp = mksobj(otyp, TRUE, FALSE);
	otmp->quan = (long) rn1(oquan, 3);
	otmp->owt = weight(otmp);
	if (otyp == ORCISH_ARROW) otmp->opoisoned = TRUE;
	mpickobj(mtmp, otmp);
}

#endif /* OVLB */
#ifdef OVL2

STATIC_OVL void
m_initweap(mtmp)
register struct monst *mtmp;
{
	register struct permonst *ptr = mtmp->data;
	register int mm = monsndx(ptr);
#ifdef REINCARNATION
	if (Is_rogue_level(&u.uz)) return;
#endif
/*
 *	first a few special cases:
 *
 *		giants get a boulder to throw sometimes.
 *		ettins get clubs
 *		kobolds get darts to throw
 *		centaurs get some sort of bow & arrows or bolts
 *		soldiers get all sorts of things.
 *		kops get clubs & cream pies.
 */
	switch (mtmp->data->mlet) {
	    case S_GIANT:
		if (rn2(2)) (void)mongets(mtmp, (ptr != &mons[PM_ETTIN]) ?
				    BOULDER : CLUB);
		break;
	    case S_HUMAN:
		if(is_mercenary(ptr)) {
		    int w1 = 0, w2 = 0;
		    switch (mm) {

			case PM_WATCHMAN:
#ifdef ARMY
			case PM_SOLDIER:
#endif
			  if (!rn2(3)) {
			      w1 = rn1(BEC_DE_CORBIN - PARTISAN + 1, PARTISAN);
			      w2 = rn2(2) ? DAGGER : KNIFE;
			  } else w1 = rn2(2) ? SPEAR : SHORT_SWORD;
			  break;
#ifdef ARMY
			case PM_SERGEANT:
			  w1 = rn2(2) ? FLAIL : MACE;
			  break;
			case PM_LIEUTENANT:
			  w1 = rn2(2) ? BROADSWORD : LONG_SWORD;
			  break;
			case PM_CAPTAIN:
#endif
			case PM_WATCH_CAPTAIN:
			  w1 = rn2(2) ? LONG_SWORD : SILVER_SABER;
			  break;
			default:
			  if (!rn2(4)) w1 = DAGGER;
			  if (!rn2(7)) w2 = SPEAR;
			  break;
		    }
		    if (w1) (void)mongets(mtmp, w1);
		    if (!w2 && w1 != DAGGER && !rn2(4)) w2 = KNIFE;
		    if (w2) (void)mongets(mtmp, w2);
		} else if (is_elf(ptr)) {
		    if (rn2(2))
			(void) mongets(mtmp,
				   rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK);
		    if (rn2(2)) (void)mongets(mtmp, ELVEN_LEATHER_HELM);
		    else if (!rn2(4)) (void)mongets(mtmp, ELVEN_BOOTS);
		    if (rn2(2)) (void)mongets(mtmp, ELVEN_DAGGER);
		    switch (rn2(3)) {
			case 0:
			    if (!rn2(4)) (void)mongets(mtmp, ELVEN_SHIELD);
			    if (rn2(3)) (void)mongets(mtmp, ELVEN_SHORT_SWORD);
			    (void)mongets(mtmp, ELVEN_BOW);
			    m_initthrow(mtmp, ELVEN_ARROW, 12);
			    break;
			case 1:
			    (void)mongets(mtmp, ELVEN_BROADSWORD);
			    if (rn2(2)) (void)mongets(mtmp, ELVEN_SHIELD);
			    break;
			case 2:
			    if (rn2(2)) {
				(void)mongets(mtmp, ELVEN_SPEAR);
				(void)mongets(mtmp, ELVEN_SHIELD);
			    }
			    break;
		    }
		    if(mtmp->data == &mons[PM_ELVENKING])
			(void)mongets(mtmp, PICK_AXE);
		}
		break;

	    case S_ANGEL:
		{
		    int spe2;
		    /* create minion stuff; can't use mongets */
		    struct obj *otmp = mksobj(LONG_SWORD, FALSE, FALSE);

		    /* maybe make it special */
		    if(!rn2(20) || is_lord(mtmp->data))
			otmp = oname(otmp, artiname(
				rn2(2) ? ART_DEMONBANE : ART_SUNSWORD), 0);
		    bless(otmp);
		    otmp->oerodeproof = TRUE;
		    spe2 = rn2(4);
		    otmp->spe = max(otmp->spe, spe2);
		    mpickobj(mtmp, otmp);

		    otmp = mksobj(!rn2(4) || is_lord(mtmp->data) ?
				  SHIELD_OF_REFLECTION : LARGE_SHIELD,
				  FALSE, FALSE);
		    otmp->cursed = FALSE;
		    otmp->oerodeproof = TRUE;
		    otmp->spe = 0;
		    mpickobj(mtmp, otmp);
		}
		break;

	    case S_HUMANOID:
		if (mm == PM_HOBBIT) {
		    switch (rn2(3)) {
			case 0:
			    (void)mongets(mtmp, DAGGER);
			    break;
			case 1:
			    (void)mongets(mtmp, ELVEN_DAGGER);
			    break;
			case 2:
			    (void)mongets(mtmp, SLING);
			    break;
		      }
		    if (!rn2(10)) (void)mongets(mtmp, ELVEN_MITHRIL_COAT);
		    if (!rn2(10)) (void)mongets(mtmp, DWARVISH_CLOAK);
		} else if (is_dwarf(ptr)) {
		    if (rn2(7)) (void)mongets(mtmp, DWARVISH_CLOAK);
		    if (rn2(7)) (void)mongets(mtmp, IRON_SHOES);
		    if (!rn2(4)) {
			(void)mongets(mtmp, DWARVISH_SHORT_SWORD);
			/* note: you can't use a mattock with a shield */
			if (rn2(2)) (void)mongets(mtmp, DWARVISH_MATTOCK);
			else {
				(void)mongets(mtmp, AXE);
				(void)mongets(mtmp, DWARVISH_ROUNDSHIELD);
			}
			(void)mongets(mtmp, DWARVISH_IRON_HELM);
			if (!rn2(3))
			    (void)mongets(mtmp, DWARVISH_MITHRIL_COAT);
		    } else {
			(void)mongets(mtmp, !rn2(3) ? PICK_AXE : DAGGER);
		    }
		}
		break;
# ifdef KOPS
	    case S_KOP:		/* create Keystone Kops with cream pies to
				 * throw. As suggested by KAA.	   [MRS]
				 */
		if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2);
		if (!rn2(3)) (void)mongets(mtmp,(rn2(2)) ? CLUB : RUBBER_HOSE);
		break;
# endif
	    case S_ORC:
		if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM);
		switch (mm != PM_ORC_CAPTAIN ? mm :
			rn2(2) ? PM_MORDOR_ORC : PM_URUK_HAI) {
		    case PM_MORDOR_ORC:
			if(!rn2(3)) (void)mongets(mtmp, SCIMITAR);
			if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHIELD);
			if(!rn2(3)) (void)mongets(mtmp, KNIFE);
			if(!rn2(3)) (void)mongets(mtmp, ORCISH_CHAIN_MAIL);
			break;
		    case PM_URUK_HAI:
			if(!rn2(3)) (void)mongets(mtmp, ORCISH_CLOAK);
			if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHORT_SWORD);
			if(!rn2(3)) (void)mongets(mtmp, IRON_SHOES);
			if(!rn2(3)) {
			    (void)mongets(mtmp, ORCISH_BOW);
			    m_initthrow(mtmp, ORCISH_ARROW, 12);
			}
			if(!rn2(3)) (void)mongets(mtmp, URUK_HAI_SHIELD);
			break;
		    default:
			if (mm != PM_ORC_SHAMAN && rn2(2))
			  (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0)
						   ? ORCISH_DAGGER : SCIMITAR);
		}
		break;
	    case S_OGRE:
		if (!rn2(mm == PM_OGRE_KING ? 3 : mm == PM_OGRE_LORD ? 6 : 12))
		    (void) mongets(mtmp, BATTLE_AXE);
		break;
	    case S_KOBOLD:
		if (!rn2(4)) m_initthrow(mtmp, DART, 12);
		break;

	    case S_CENTAUR:
		if (rn2(2)) {
		    if(ptr == &mons[PM_FOREST_CENTAUR]) {
			(void)mongets(mtmp, BOW);
			m_initthrow(mtmp, ARROW, 12);
		    } else {
			(void)mongets(mtmp, CROSSBOW);
			m_initthrow(mtmp, CROSSBOW_BOLT, 12);
		    }
		}
		break;
	    case S_WRAITH:
		(void)mongets(mtmp, KNIFE);
		(void)mongets(mtmp, LONG_SWORD);
		break;
	    case S_DEMON:
		switch (mm) {
		    case PM_BALROG:
			(void)mongets(mtmp, BULLWHIP);
			(void)mongets(mtmp, BROADSWORD);
			break;
		    case PM_ORCUS:
			(void)mongets(mtmp, WAN_DEATH); /* the Wand of Orcus */
			break;
		    case PM_HORNED_DEVIL:
			(void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP);
			break;
		    case PM_ICE_DEVIL:
			if (!rn2(4)) (void)mongets(mtmp, SPEAR);
			break;
		    case PM_ASMODEUS:
			(void)mongets(mtmp, WAN_COLD);
			break;
		    case PM_DISPATER:
			(void)mongets(mtmp, WAN_STRIKING);
			break;
		    case PM_YEENOGHU:
			(void)mongets(mtmp, FLAIL);
			break;
		}
		/* prevent djinnis and mail daemons from leaving objects when
		 * they vanish
		 */
		if (!is_demon(ptr)) break;
		/* fall thru */
/*
 *	Now the general case, ~40% chance of getting some type
 *	of weapon. TODO: Add more weapons types (use bigmonst());
 */
	    default:
		switch(rnd(12)) {
		    case 1:
			m_initthrow(mtmp, DART, 12);
			break;
		    case 2:
			(void) mongets(mtmp, CROSSBOW);
			m_initthrow(mtmp, CROSSBOW_BOLT, 12);
			break;
		    case 3:
			(void) mongets(mtmp, BOW);
			m_initthrow(mtmp, ARROW, 12);
			break;
		    case 4:
			m_initthrow(mtmp, DAGGER, 3);
			break;
		    case 5:
			(void) mongets(mtmp, AKLYS);
			break;
		    default:
			break;
		}
		break;
	}
#ifdef MUSE
	if ((int) mtmp->m_lev > rn2(70))
		(void) mongets(mtmp, rnd_offensive_item(mtmp));
#endif
}

#endif /* OVL2 */
#ifdef OVL1

static void
m_initinv(mtmp)
register struct	monst	*mtmp;
{
	register int cnt;
	register struct obj *otmp;
	register struct permonst *ptr = mtmp->data;
#ifdef REINCARNATION
	if (Is_rogue_level(&u.uz)) return;
#endif
/*
 *	Soldiers get armour & rations - armour approximates their ac.
 *	Nymphs may get mirror or potion of object detection.
 */
	switch(ptr->mlet) {

	    case S_HUMAN:
		if(is_mercenary(ptr)) {
		    register int mac;
#ifdef MUSE
		    switch(monsndx(ptr)) {
			case PM_GUARD: mac = -1; break;
# ifdef ARMY
			case PM_SOLDIER: mac = 3; break;
			case PM_SERGEANT: mac = 0; break;
			case PM_LIEUTENANT: mac = -2; break;
			case PM_CAPTAIN: mac = -3; break;
# endif
			case PM_WATCHMAN: mac = 3; break;
			case PM_WATCH_CAPTAIN: mac = -2; break;
			default: impossible("odd mercenary %d?", monsndx(ptr));
				mac = 0;
				break;
		    }
#else
		    mac = ptr->ac;
#endif

		    if (mac < -1 && rn2(5))
			mac += 7 + mongets(mtmp, (rn2(5)) ?
					   PLATE_MAIL : CRYSTAL_PLATE_MAIL);
		    else if (mac < 3 && rn2(5))
			mac += 6 + mongets(mtmp, (rn2(3)) ?
					   SPLINT_MAIL : BANDED_MAIL);
		    else if (rn2(5))
			mac += 3 + mongets(mtmp, (rn2(3)) ?
					   RING_MAIL : STUDDED_LEATHER_ARMOR);
		    else
			mac += 2 + mongets(mtmp, LEATHER_ARMOR);

		    if (mac < 10 && rn2(3))
			mac += 1 + mongets(mtmp, HELMET);
		    else if (mac < 10 && rn2(2))
			mac += 1 + mongets(mtmp, DENTED_POT);
		    if (mac < 10 && rn2(3))
			mac += 1 + mongets(mtmp, SMALL_SHIELD);
		    else if (mac < 10 && rn2(2))
			mac += 2 + mongets(mtmp, LARGE_SHIELD);
		    if (mac < 10 && rn2(3))
			mac += 1 + mongets(mtmp, LOW_BOOTS);
		    else if (mac < 10 && rn2(2))
			mac += 2 + mongets(mtmp, HIGH_BOOTS);
		    if (mac < 10 && rn2(3))
			mac += 1 + mongets(mtmp, LEATHER_GLOVES);
		    else if (mac < 10 && rn2(2))
			mac += 1 + mongets(mtmp, ELVEN_CLOAK);

#ifndef MUSE
		    if (mac != 10 && rn2(5)) {	/* make up the difference */
			otmp = mksobj(RIN_PROTECTION, FALSE, FALSE);
			otmp->spe = (10 - mac + rn2(3) - rn2(3));
			if(otmp->spe < 0) curse(otmp);
			mpickobj(mtmp, otmp);
		    }
#endif
#ifdef ARMY
		    if(ptr != &mons[PM_GUARD] &&
			ptr != &mons[PM_WATCHMAN] &&
			ptr != &mons[PM_WATCH_CAPTAIN]) {
			if (!rn2(3)) (void) mongets(mtmp, K_RATION);
			if (!rn2(2)) (void) mongets(mtmp, C_RATION);
# ifdef MUSE
			if (ptr != &mons[PM_SOLDIER] && !rn2(3))
				(void) mongets(mtmp, BUGLE);
# endif
		    } else
#endif
			   if (ptr == &mons[PM_WATCHMAN] && rn2(3))
				(void) mongets(mtmp, TIN_WHISTLE);
		} else if (ptr == &mons[PM_SHOPKEEPER]) {
		    (void) mongets(mtmp,SKELETON_KEY);
		}
		break;

	    case S_NYMPH:
		if(!rn2(2)) (void) mongets(mtmp, MIRROR);
		if(!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION);
		break;

	    case S_GIANT:
		if (ptr == &mons[PM_MINOTAUR])
		    (void) mongets(mtmp, WAN_DIGGING);
		else if (is_giant(ptr)) {
		    for(cnt = rn2((int)(mtmp->m_lev / 2)); cnt; cnt--) {
			    otmp = mksobj(rnd_class(DILITHIUM_CRYSTAL,LUCKSTONE-1),FALSE,FALSE);
			    otmp->quan = (long) rn1(2, 3);
			    otmp->owt = weight(otmp);
			    mpickobj(mtmp, otmp);
		    }
		}
		break;
	    case S_WRAITH:
		if (ptr == &mons[PM_NAZGUL]) {
			otmp = mksobj(RIN_INVISIBILITY, FALSE, FALSE);
			curse(otmp);
			mpickobj(mtmp, otmp);
		}
		break;
	    case S_QUANTMECH:
		if (!rn2(20)) {
			struct obj *cat;

			otmp = mksobj(LARGE_BOX, FALSE, FALSE);
	/* actually, whether this is a corpse or a live cat shouldn't
	   really be decided until the box is opened... */
			cat = mksobj(CORPSE, FALSE, FALSE);
			cat->corpsenm = PM_HOUSECAT;
			cat->owt = weight(cat);
			cat = oname(cat, "Schroedinger's Cat", FALSE);
			cat->nobj = otmp->cobj;
			otmp->cobj = cat;
			otmp->owt = weight(otmp);
			mpickobj(mtmp, otmp);
		}
		break;
	    case S_LEPRECHAUN:
		mtmp->mgold = (long) d(level_difficulty(), 30);
		break;
	    default:
		break;
	}

#ifdef ARMY	/* ordinary soldiers rarely have access to magic (or gold :-) */
	if (ptr == &mons[PM_SOLDIER] && rn2(13)) return;
#endif
#ifdef MUSE
	if ((int) mtmp->m_lev > rn2(30))
		(void) mongets(mtmp, rnd_defensive_item(mtmp));
	if ((int) mtmp->m_lev > rn2(100))
		(void) mongets(mtmp, rnd_misc_item(mtmp));
#endif
	if (likes_gold(ptr) && !mtmp->mgold && !rn2(5))
		mtmp->mgold =
		      (long) d(level_difficulty(), mtmp->minvent ? 5 : 10);
}

/*
 * called with [x,y] = coordinates;
 *	[0,0] means anyplace
 *	[u.ux,u.uy] means: near player (if !in_mklev)
 *
 *	In case we make a monster group, only return the one at [x,y].
 */
struct monst *
makemon(ptr, x, y)
register struct permonst *ptr;
register int	x, y;
{
	register struct monst *mtmp;
	register int	ct;
	boolean anything = (!ptr);
	boolean byyou = (x == u.ux && y == u.uy);

	/* if caller wants random location, do it here */
	if(x == 0 && y == 0) {
		int tryct = 0;	/* careful with bigrooms */
		do {
			x = rn1(COLNO-3,2);
			y = rn2(ROWNO);
		} while(!goodpos(x, y, (struct monst *)0, ptr) ||
			(!in_mklev && tryct++ < 50 && cansee(x, y)));
	} else if (byyou && !in_mklev) {
		coord bypos;

		if(enexto(&bypos, u.ux, u.uy, ptr)) {
			x = bypos.x;
			y = bypos.y;
		} else
			return((struct monst *)0);
	}

	/* if a monster already exists at the position, return */
	if(MON_AT(x, y))
		return((struct monst *) 0);

	if(ptr){
		/* if you are to make a specific monster and it has
		   already been genocided, return */
		if(ptr->geno & G_GENOD) return((struct monst *) 0);
	} else {
		/* make a random (common) monster that can survive here.
		 * (the special levels ask for random monsters at specific
		 * positions, causing mass drowning on the medusa level,
		 * for instance.)
		 */
		int tryct = 0;	/* maybe there are no good choices */
		do {
			if(!(ptr = rndmonst())) {
#ifdef DEBUG
			    pline("Warning: no monster.");
#endif
			    return((struct monst *) 0);	/* no more monsters! */
			}
		} while(!goodpos(x, y, (struct monst *)0, ptr) && tryct++ < 50);
	}
	/* if it's unique, don't ever make it again */
	if (ptr->geno & G_UNIQ) ptr->geno |= G_EXTINCT;

	mtmp = newmonst(ptr->pxlth);
	*mtmp = zeromonst;		/* clear all entries in structure */
	for(ct = 0; ct < ptr->pxlth; ct++)
		((char *) &(mtmp->mextra[0]))[ct] = 0;
	mtmp->nmon = fmon;
	fmon = mtmp;
	mtmp->m_id = flags.ident++;
	mtmp->data = ptr;
	mtmp->mxlth = ptr->pxlth;

	mtmp->m_lev = adj_lev(ptr);
	if (is_golem(ptr))
	    mtmp->mhpmax = mtmp->mhp = golemhp(monsndx(ptr));
	else if (is_rider(ptr)) {
		/* We want low HP, but a high mlevel so they can attack well */
		mtmp->mhpmax = mtmp->mhp = d(10,8);
	} else if(ptr->mlevel > 49) {
	    /* "special" fixed hp monster
	     * the hit points are encoded in the mlevel in a somewhat strange
	     * way to fit in the 50..127 positive range of a signed character
	     * above the 1..49 that indicate "normal" monster levels */
	    mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6);
	    mtmp->m_lev = mtmp->mhp / 4;	/* approximation */
	} else if((ptr->mlet == S_DRAGON) && (ptr >= &mons[PM_GRAY_DRAGON]))
	    mtmp->mhpmax = mtmp->mhp = mtmp->m_lev*8;
	else if(!mtmp->m_lev) mtmp->mhpmax = mtmp->mhp = rnd(4);
	else if(is_home_elemental(ptr))
	    mtmp->mhpmax = mtmp->mhp = 3 * d((int)mtmp->m_lev, 8);
	else mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8);

	if (is_female(ptr)) mtmp->female = TRUE;
	else if (is_male(ptr)) mtmp->female = FALSE;
	else mtmp->female = rn2(2);	/* ignored for neuters */

	place_monster(mtmp, x, y);
	mtmp->mcansee = mtmp->mcanmove = TRUE;
	mtmp->mpeaceful = peace_minded(ptr);

	switch(ptr->mlet) {
		case S_MIMIC:
			set_mimic_sym(mtmp);
			break;
		case S_SPIDER:
		case S_SNAKE:
			if(in_mklev)
			    if(x && y)
				(void) mkobj_at(0, x, y, TRUE);
			if(hides_under(ptr) && OBJ_AT(x, y))
			    mtmp->mundetected = TRUE;
			break;
		case S_STALKER:
		case S_EEL:
			mtmp->minvis = TRUE;
			break;
		case S_LEPRECHAUN:
			mtmp->msleep = TRUE;
			break;
		case S_JABBERWOCK:
		case S_NYMPH:
			if(rn2(5) && !u.uhave.amulet) mtmp->msleep = TRUE;
			break;
		case S_ORC:
			if(pl_character[0] == 'E') mtmp->mpeaceful = FALSE;
			break;
		case S_UNICORN:
			if (sgn(u.ualign.type) == sgn(ptr->maligntyp))
				mtmp->mpeaceful = TRUE;
			break;
	}
	if (ptr == &mons[PM_CHAMELEON]) {
		/* If you're protected with a ring, don't create
		 * any shape-changing chameleons -dgk
		 */
		if (Protection_from_shape_changers)
			mtmp->cham = FALSE;
		else {
			mtmp->cham = TRUE;
			(void) newcham(mtmp, rndmonst());
		}
	} else if (ptr == &mons[PM_WIZARD_OF_YENDOR]) {
		mtmp->iswiz = TRUE;
		flags.no_of_wizards++;
	} else if (ptr == &mons[PM_VLAD_THE_IMPALER])
		(void) mongets(mtmp, CANDELABRUM_OF_INVOCATION);
#ifdef MULDGN
	else if (ptr->msound == MS_NEMESIS)
		(void) mongets(mtmp, BELL_OF_OPENING);
#else
	else if (ptr == &mons[PM_MEDUSA])
		(void) mongets(mtmp, BELL_OF_OPENING);
#endif

	if(in_mklev) {
		if(((is_ndemon(ptr)) ||
		    (ptr == &mons[PM_WUMPUS]) ||
		    (ptr == &mons[PM_LONG_WORM]) ||
		    (ptr == &mons[PM_GIANT_EEL])) && !u.uhave.amulet && rn2(5))
			mtmp->msleep = TRUE;
	} else {
		if(byyou) {
			newsym(mtmp->mx,mtmp->my);
			set_apparxy(mtmp);
		}
	}
	if(is_dprince(ptr)) {
	    mtmp->mpeaceful = mtmp->minvis = TRUE;
	    if (uwep && uwep->oartifact == ART_EXCALIBUR)
		mtmp->mpeaceful = mtmp->mtame = FALSE;
	}
	if ( (ptr == &mons[PM_LONG_WORM]) && (mtmp->wormno = get_wormno()) ) {
	    /* we can now create worms with tails - 11/91 */
	    initworm(mtmp, rn2(5));
	    if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, x, y);
	}
	set_malign(mtmp);		/* having finished peaceful changes */
	if(anything) {
	    if((ptr->geno & G_SGROUP) && rn2(2))
		m_initsgrp(mtmp, mtmp->mx, mtmp->my);
	    else if(ptr->geno & G_LGROUP) {
			if(rn2(3))  m_initlgrp(mtmp, mtmp->mx, mtmp->my);
			else	    m_initsgrp(mtmp, mtmp->mx, mtmp->my);
	    }
	}

	if(is_armed(ptr))
		m_initweap(mtmp);	/* equip with weapons / armor */
	m_initinv(mtmp);    /* add on a few special items incl. more armor */
#ifdef MUSE
	m_dowear(mtmp, TRUE);
#endif

	if (!in_mklev)
	    newsym(mtmp->mx,mtmp->my);	/* make sure the mon shows up */

	return(mtmp);
}

boolean
enexto(cc, xx, yy, mdat)
coord *cc;
register xchar xx, yy;
struct permonst *mdat;
{
	register xchar x,y;
	coord foo[15], *tfoo;
	int range, i;
	int xmin, xmax, ymin, ymax;

	tfoo = foo;
	range = 1;
	do {	/* full kludge action. */
		xmin = max(1, xx-range);
		xmax = min(COLNO-1, xx+range);
		ymin = max(0, yy-range);
		ymax = min(ROWNO-1, yy+range);

		for(x = xmin; x <= xmax; x++)
			if(goodpos(x, ymin, (struct monst *)0, mdat)) {
				tfoo->x = x;
#ifdef MAC_MPW32
				( tfoo ) -> y = ymin ;
				tfoo ++ ;
#else
				(tfoo++)->y = ymin;
#endif
				if(tfoo == &foo[15]) goto foofull;
			}
		for(x = xmin; x <= xmax; x++)
			if(goodpos(x, ymax, (struct monst *)0, mdat)) {
				tfoo->x = x;
#ifdef MAC_MPW32
				( tfoo ) -> y = ymax ;
				tfoo ++ ;
#else
				(tfoo++)->y = ymax;
#endif
				if(tfoo == &foo[15]) goto foofull;
			}
		for(y = ymin+1; y < ymax; y++)
			if(goodpos(xmin, y, (struct monst *)0, mdat)) {
				tfoo->x = xmin;
#ifdef MAC_MPW32
				( tfoo ) -> y = y ;
				tfoo ++ ;
#else
				(tfoo++)->y = y;
#endif
				if(tfoo == &foo[15]) goto foofull;
			}
		for(y = ymin+1; y < ymax; y++)
			if(goodpos(xmax, y, (struct monst *)0, mdat)) {
				tfoo->x = xmax;
#ifdef MAC_MPW32
				( tfoo ) -> y = y ;
				tfoo ++ ;
#else
				(tfoo++)->y = y;
#endif
				if(tfoo == &foo[15]) goto foofull;
			}
		range++;
		if(range > ROWNO && range > COLNO) return FALSE;
	} while(tfoo == foo);
foofull:
	i = rn2((int)(tfoo - foo));
	cc->x = foo[i].x;
	cc->y = foo[i].y;
	return TRUE;
}

int
goodpos(x, y, mtmp, mdat)
int x,y;
struct monst *mtmp;	/* existing monster being moved, if any */
struct permonst *mdat;
{
	struct monst *mtmp2;

	if (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 || MON_AT(x, y))
		return 0;

	/* in many cases, we're trying to create a new monster, which
	 * can't go on top of the player or any existing monster.
	 * however, occasionally we are relocating engravings or objects,
	 * which could be colocated and thus get restricted a bit too much.
	 * oh well.
	 */
	if (x == u.ux && y == u.uy) return 0;
	if ((mtmp2 = m_at(x, y)) && mtmp != mtmp2) return 0;

	if (mdat) {
	    if (IS_POOL(levl[x][y].typ))
		if (mdat == &playermon &&
		    (HLevitation || Wwalking || Magical_breathing))
			return 1;
		else	return (is_flyer(mdat) || is_swimmer(mdat));
	    if (levl[x][y].typ == LAVAPOOL)
		if (mdat == &playermon && (HLevitation))
			return 1;
		else return
			(is_flyer(mdat) || (mdat == &mons[PM_FIRE_ELEMENTAL]));
	    if (passes_walls(mdat)) return 1;
	}
	if (!ACCESSIBLE(levl[x][y].typ)) return 0;
	if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
		return 0;
	if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
		return 0;
	return 1;
}

#endif /* OVL1 */
#ifdef OVLB

/*
 * rloc_to()
 *
 * Pulls a monster from its current position and places a monster at
 * a new x and y.  If oldx is 0, then the monster was not in the levels.monsters
 * array.  However, if oldx is 0, oldy may still have a value because mtmp is a
 * migrating_mon.  Worm tails are always placed randomly around the head of
 * the worm.
 */

void
rloc_to(mtmp, x, y)
	struct monst *mtmp;
	register int x, y;
{
	register int oldx = mtmp->mx, oldy = mtmp->my;

	if(x == mtmp->mx && y == mtmp->my) /* that was easy */
		return;

	if (oldx) {				/* "pick up" monster */
	    if(mtmp->wormno)
		remove_worm(mtmp);
	    else {
		remove_monster(oldx, oldy);
		newsym(oldx, oldy);		/* update old location */
	    }
	}

	place_monster(mtmp, x, y);		/* put monster down */

	if(mtmp->wormno)			/* now put down tail */
		place_worm_tail_randomly(mtmp, x, y);

	if(u.ustuck == mtmp){
		if(u.uswallow) {
			u.ux = x;
			u.uy = y;
			docrt();
		} else	u.ustuck = 0;
	}

	newsym(x, y);				/* update new location */
	set_apparxy(mtmp);			/* orient monster */
}

#endif /* OVLB */
#ifdef OVL2

void
rloc(mtmp)
	struct monst *mtmp;
{
	register int x = xupstair, y = yupstair, trycount;

	/* if the wiz teleports away to heal, try the up staircase,
	   to block the player's escaping before he's healed */
	if (!mtmp->iswiz || !goodpos(x, y, mtmp, mtmp->data)) {
	    trycount = 0;
	    do {
		x = rn1(COLNO-3,2);
		y = rn2(ROWNO);
	    } while(!goodpos(x,y,mtmp,mtmp->data) && ++trycount < 1000);
	    /* last ditch attempt to find a good place */
	    if (trycount >= 1000) {
		for (x = 2; x < COLNO - 1; x++)
		    for (y = 0; y < ROWNO; y++)
			if (goodpos(x,y,mtmp,mtmp->data))
			    goto found_atlast;
		/* level either full of monsters or somehow faulty */
		impossible("rloc(): couldn't relocate monster");
		return;
	    }
	}
found_atlast:;
	rloc_to(mtmp, x, y);
}

void
rloc_shk(mtmp)   /* to be used when teleporting a shopkeeper */
struct monst *mtmp;
{
	register int x, y, ox, oy, trycount;

	if(!mtmp->isshk) return;
	trycount = 0;
	do {
		x = rn1(COLNO-3,2);
		y = rn2(ROWNO);
	} while(!goodpos(x,y,mtmp,mtmp->data) && ++trycount < 1000);
	/* last ditch attempt to find a good place */
	if (trycount >= 1000) {
		for (x = 2; x < COLNO - 1; x++)
		    for (y = 0; y < ROWNO; y++)
			if (goodpos(x,y,mtmp,mtmp->data))
			    goto found_ok;
		/* this really shouldn't happen - after all, shopkeeper's
		   original position should always be available */
		impossible("rloc_shk(): couldn't relocate shopkeeper");
		return;
	}
found_ok:;
	ox = mtmp->mx;
	oy = mtmp->my;
	rloc_to(mtmp, x, y);
	make_angry_shk(mtmp, ox, oy);
}

#endif /* OVL2 */
#ifdef OVLB

void
vloc(mtmp)
struct monst *mtmp;
{
	register struct mkroom *croom = search_special(VAULT);
	coord c;

	if(croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, mtmp->data)) {
		rloc_to(mtmp, c.x, c.y);
		return;
	}
	rloc(mtmp);
}

#endif /* OVLB */
#ifdef OVL0

static boolean
cmavail()	/* return TRUE if "common" monsters can be generated */
{
	struct permonst *ptr;

	for(ptr = &mons[0]; ptr != &mons[NUMMONS]; ptr++)
	   if(!uncommon(ptr))  return TRUE;

	return FALSE;
}

/*
 *	shift the probability of a monster's generation by
 *	comparing the dungeon alignment and monster alignment.
 *	return an integer in the range of 0-5.
 */
static int
align_shift(ptr)
register struct permonst *ptr;
{
    static long NEARDATA oldmoves = 0L;	/* != 1, starting value of moves */
    static s_level NEARDATA *lev;
    register int alshift;

    if(oldmoves != moves) {
	lev = Is_special(&u.uz);
	oldmoves = moves;
    }
    switch((lev) ? lev->flags.align : dungeons[u.uz.dnum].flags.align) {
    default:	/* just in case */
    case AM_NONE:	alshift = 0;
			break;
    case AM_LAWFUL:	alshift = (ptr->maligntyp+20)/(2*ALIGNWEIGHT);
			break;
    case AM_NEUTRAL:	alshift = (20 - abs(ptr->maligntyp))/ALIGNWEIGHT;
			break;
    case AM_CHAOTIC:	alshift = (-(ptr->maligntyp-20))/(2*ALIGNWEIGHT);
			break;
    }
    return alshift;
}

struct	permonst *
rndmonst()		/* select a random monster */
{
	register struct permonst *ptr;
	register int i, ct;
	register int zlevel;
	static int NEARDATA minmlev, NEARDATA maxmlev, NEARDATA accept;
	static long NEARDATA oldmoves = 0L;	/* != 1, starting value of moves */
#ifdef REINCARNATION
	static boolean NEARDATA upper;
#endif
	static boolean NEARDATA elemlevel;

#ifdef MULDGN
	if(u.uz.dnum == quest_dnum && (ptr = qt_montype())) return(ptr);
#endif
	if(oldmoves != moves) {		/* must recalculate accept */
	    oldmoves = moves;
	    zlevel = level_difficulty();
	    if(!cmavail()) {
#ifdef DEBUG
		pline("cmavail() fails!");
#endif
		return((struct permonst *) 0);
	    }

	    /* determine the level of the weakest monster to make. */
	    minmlev = zlevel/6;
	    /* determine the level of the strongest monster to make. */
	    maxmlev = (zlevel + u.ulevel)>>1;
#ifdef REINCARNATION
	    upper = Is_rogue_level(&u.uz);
#endif
	    elemlevel = In_endgame(&u.uz) && !Is_astralevel(&u.uz);
/*
 *	Find out how many monsters exist in the range we have selected.
 */
	    accept = 0;
	    for(ct = 0, ptr = &mons[0] ; ptr != &mons[NUMMONS]; ct++, ptr++) {
		if(tooweak(ct, minmlev) || toostrong(ct, maxmlev))
		    continue;
#ifdef REINCARNATION
		if(upper && !isupper(def_monsyms[ptr->mlet])) continue;
#endif
		if(elemlevel && wrong_elem_type(ptr)) continue;
		if(uncommon(ptr)) continue;
		accept += (ptr->geno & G_FREQ);
		accept += align_shift(ptr);
	    }
	}

	if(!accept) {
#ifdef DEBUG
		pline("no accept!");
#endif
		return((struct permonst *) 0);
	}
/*
 *	Now, select a monster at random.
 */
	ct = rnd(accept);
	for(i = 0,ptr = &mons[0]; ptr != &mons[NUMMONS] && ct > 0; i++,ptr++) {
		if(tooweak(i, minmlev) || toostrong(i, maxmlev))
		    continue;
#ifdef REINCARNATION
		if(upper & !isupper(def_monsyms[ptr->mlet])) continue;
#endif
		if(elemlevel && wrong_elem_type(ptr)) continue;
		if(uncommon(ptr)) continue;
		ct -= (ptr->geno & G_FREQ);
		ct -= align_shift(ptr);
	}
	if(ct > 0) {
#ifdef DEBUG
		pline("no count!");
#endif
		return((struct permonst *) 0);
	}
	return(--ptr);	/* subtract extra increment */
}

#endif /* OVL0 */
#ifdef OVL1

/*	The routine below is used to make one of the multiple types
 *	of a given monster class.  The second parameter specifies a
 *	special casing bit mask to allow any of the normal genesis
 *	masks to be deactivated.  Returns 0 if no monsters
 *	in that class can be made.
 */

struct permonst *
mkclass(class,spc)
char	class;
int	spc;
{
	register int	first, last, num = 0;
	int maxmlev, mask = (G_GENOD | G_EXTINCT | G_NOGEN | G_UNIQ) & ~spc;

	maxmlev = level_difficulty() >> 1;
	if(class < 1 || class >= MAXMCLASSES) {
	    impossible("mkclass called with bad class!");
	    return((struct permonst *) 0);
	}
/*	Assumption #1:	monsters of a given class are contiguous in the
 *			mons[] array.
 */
	for(first = 0; first < NUMMONS; first++)
	    if (mons[first].mlet == class) break;
	if (first == NUMMONS) return((struct permonst *) 0);

	for(last = first; last < NUMMONS && mons[last].mlet == class; last++)
	    if(!(mons[last].geno & mask)) {
		/* consider it */
		if(num && toostrong(last, maxmlev) && rn2(2)) break;
		num += mons[last].geno & G_FREQ;
	    }

	if(!num) return((struct permonst *) 0);

/*	Assumption #2:	monsters of a given class are presented in ascending
 *			order of strength.
 */
	for(num = rnd(num); num > 0; first++)
	    if(!(mons[first].geno & mask)) {
		/* skew towards lower value monsters at lower exp. levels */
		if(adj_lev(&mons[first]) > (u.ulevel*2)) num--;
		num -= mons[first].geno & G_FREQ;
	    }
	first--; /* correct an off-by-one error */

	return(&mons[first]);
}

int
adj_lev(ptr)	/* adjust strength of monsters based on u.uz and u.ulevel */
register struct permonst *ptr;
{
	int	tmp, tmp2;

	if((tmp = ptr->mlevel) > 49) return(50); /* "special" demons/devils */
	tmp2 = (level_difficulty() - tmp);
	if(tmp2 < 0) tmp--;		/* if mlevel > u.uz decrement tmp */
	else tmp += (tmp2 / 5);		/* else increment 1 per five diff */

	tmp2 = (u.ulevel - ptr->mlevel);	/* adjust vs. the player */
	if(tmp2 > 0) tmp += (tmp2 / 4);		/* level as well */

	tmp2 = (3 * ((int) ptr->mlevel))/ 2;	/* crude upper limit */
	return((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */
}

#endif /* OVL1 */
#ifdef OVLB

struct permonst *
grow_up(mtmp,victim)		/* mon mtmp "grows up" to a bigger version. */
register struct monst *mtmp;
register struct monst *victim;
{
	register int newtype;
	register struct permonst *ptr = mtmp->data;

	if (ptr->mlevel >= 50 || is_golem(ptr) || is_home_elemental(ptr)
		|| is_mplayer(ptr))
	    /* doesn't grow up, has strange hp calculation so might be
	     * weakened by tests below */
	    return ptr;

	if (victim) {
	    mtmp->mhpmax = mtmp->mhpmax + (1 + rn2((int)victim->m_lev+1));
	    if (mtmp->mhpmax <= (8 * (int)mtmp->m_lev)
			|| (mtmp->m_lev == 0 && mtmp->mhpmax <= 4))
		/* not ready to grow up */
		return ptr;
	}
#ifdef MUSE
	/* else it's a gain level potion; always go up a level */
	else {
	    int foo=rnd(8);

	    mtmp->mhp += foo;
	    mtmp->mhpmax += foo;
	}
#endif

	newtype = little_to_big(monsndx(ptr));
	if ((int) (++mtmp->m_lev) >= mons[newtype].mlevel
					&& newtype != monsndx(ptr)) {
		if (mons[newtype].geno & G_GENOD) { /* allow G_EXTINCT */
			pline("As %s grows up into %s, %s dies!",
				mon_nam(mtmp),
				an(mons[newtype].mname),
				mon_nam(mtmp));
			mondied(mtmp);
			return (struct permonst *)0;
		}
		mtmp->data = &mons[newtype];
		mtmp->m_lev = mons[newtype].mlevel;
	}
	if (newtype == monsndx(ptr) && victim &&
	    (int) mtmp->m_lev > (3*(int)mtmp->data->mlevel) / 2)
		mtmp->m_lev = (3*(int)mtmp->data->mlevel) / 2;
	if (mtmp->m_lev > 0) {
	    if (mtmp->mhp > (int) mtmp->m_lev * 8)
		mtmp->mhp = mtmp->m_lev * 8;
	    if (mtmp->mhpmax > (int) mtmp->m_lev * 8)
		mtmp->mhpmax = mtmp->m_lev * 8;
	}
	return(mtmp->data);
}

#endif /* OVLB */
#ifdef OVL1

int
mongets(mtmp, otyp)
register struct monst *mtmp;
register int otyp;
{
	register struct obj *otmp;

#ifdef MUSE
	if (!otyp) return 0;
#endif
	if((otmp = (otyp) ? mksobj(otyp,TRUE,FALSE) : mkobj((char)otyp,FALSE))) {
	    if (mtmp->data->mlet == S_DEMON) {
		/* demons always get cursed objects */
		curse(otmp);
	    } else if(is_lminion(mtmp->data)) {
		/* lawful minions don't get cursed, bad, or rusting objects */
		otmp->cursed = FALSE;
		if(otmp->spe < 0) otmp->spe = 0;
		otmp->oerodeproof = TRUE;
	    } else if(is_mplayer(mtmp->data) && is_sword(otmp))
			otmp->spe = (3 + rn2(4));
	    if(otmp->otyp == CANDELABRUM_OF_INVOCATION) {
		otmp->spe = 0;
		otmp->age = 0L;
		otmp->lamplit = FALSE;
		otmp->blessed = otmp->cursed = FALSE;
	    }
	    mpickobj(mtmp, otmp);
	    return(otmp->spe);
	} else return(0);
}

#endif /* OVL1 */
#ifdef OVLB

int
golemhp(type)
int type;
{
	switch(type) {
		case PM_STRAW_GOLEM: return 20;
		case PM_ROPE_GOLEM: return 30;
		case PM_LEATHER_GOLEM: return 40;
		case PM_WOOD_GOLEM: return 50;
		case PM_FLESH_GOLEM: return 40;
		case PM_CLAY_GOLEM: return 50;
		case PM_STONE_GOLEM: return 60;
		case PM_IRON_GOLEM: return 80;
		default: return 0;
	}
}

#endif /* OVLB */
#ifdef OVL1

/*
 *	Alignment vs. yours determines monster's attitude to you.
 *	( some "animal" types are co-aligned, but also hungry )
 */
boolean
peace_minded(ptr)
register struct permonst *ptr;
{
	aligntyp mal = ptr->maligntyp, ual = u.ualign.type;

	if (always_peaceful(ptr)) return TRUE;
	if (always_hostile(ptr)) return FALSE;
#ifdef MULDGN
	if (ptr->msound == MS_LEADER || ptr->msound == MS_GUARDIAN)
		return TRUE;
	if (ptr->msound == MS_NEMESIS)	return FALSE;
#endif

	/* the monster is hostile if its alignment is different from the
	 * player's */
	if (sgn(mal) != sgn(ual)) return FALSE;

	/* Negative monster hostile to player with Amulet. */
	if (mal < A_NEUTRAL && u.uhave.amulet) return FALSE;

	/* minions are hostile to players that have strayed at all */
	if (is_minion(ptr)) return(u.ualign.record >= 0);

	/* Last case:  a chance of a co-aligned monster being
	 * hostile.  This chance is greater if the player has strayed
	 * (u.ualign.record negative) or the monster is not strongly aligned.
	 */
	return !!rn2(16 + (u.ualign.record < -15 ? -15 : u.ualign.record)) &&
		!!rn2(2 + abs(mal));
}

/* Set malign to have the proper effect on player alignment if monster is
 * killed.  Negative numbers mean it's bad to kill this monster; positive
 * numbers mean it's good.  Since there are more hostile monsters than
 * peaceful monsters, the penalty for killing a peaceful monster should be
 * greater than the bonus for killing a hostile monster to maintain balance.
 * Rules:
 *   it's bad to kill peaceful monsters, potentially worse to kill always-
 *	peaceful monsters
 *   it's never bad to kill a hostile monster, although it may not be good
 */
void
set_malign(mtmp)
struct monst *mtmp;
{
	schar mal = mtmp->data->maligntyp;
	boolean coaligned;

	if (mtmp->ispriest || mtmp->isminion) {
		/* some monsters have individual alignments; check them */
		if (mtmp->ispriest)
			mal = EPRI(mtmp)->shralign;
		else if (mtmp->isminion)
			mal = EMIN(mtmp)->min_align;
		/* unless alignment is none, set mal to -5,0,5 */
		/* (see align.h for valid aligntyp values)     */
		if(mal != A_NONE)
			mal *= 5;
	}

	coaligned = (sgn(mal) == sgn(u.ualign.type));
#ifdef MULDGN
	if (mtmp->data->msound == MS_LEADER) {
		mtmp->malign = -20;
	} else
#endif
	      if (mal == A_NONE) {
		if (mtmp->mpeaceful)
			mtmp->malign = 0;
		else
			mtmp->malign = 20;	/* really hostile */
	} else if (always_peaceful(mtmp->data)) {
		if (mtmp->mpeaceful)
			mtmp->malign = -3*max(5,abs(mal));
		else
			mtmp->malign = 3*max(5,abs(mal)); /* renegade */
	} else if (always_hostile(mtmp->data)) {
		if (coaligned)
			mtmp->malign = 0;
		else
			mtmp->malign = max(5,abs(mal));
	} else if (coaligned) {
		if (mtmp->mpeaceful)
			mtmp->malign = -3*max(3,abs(mal));
		else	/* renegade */
			mtmp->malign = max(3,abs(mal));
	} else	/* not coaligned and therefore hostile */
		mtmp->malign = abs(mal);
}

#endif /* OVL1 */
#ifdef OVLB

static char NEARDATA syms[] = {
	MAXOCLASSES, MAXOCLASSES+1, RING_CLASS, WAND_CLASS, WEAPON_CLASS,
	FOOD_CLASS, GOLD_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS,
	AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS,
	S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF,
};

void
set_mimic_sym(mtmp)		/* KAA, modified by ERS */
register struct monst *mtmp;
{
	int typ, roomno, rt;
	unsigned appear, ap_type;
	int s_sym;
	struct obj *otmp;
	int mx, my;

	if (!mtmp) return;
	mx = mtmp->mx; my = mtmp->my;
	typ = levl[mx][my].typ;
					/* only valid for INSIDE of room */
	roomno = levl[mx][my].roomno - ROOMOFFSET;
	if (roomno >= 0)
		rt = rooms[roomno].rtype;
#ifdef SPECIALIZATION
	else if (IS_ROOM(typ))
		rt = OROOM,  roomno = 0;
#endif
	else	rt = 0;	/* roomno < 0 case for GCC_WARN */

	if (OBJ_AT(mx, my)) {
		ap_type = M_AP_OBJECT;
		appear = level.objects[mx][my]->otyp;
	} else if (IS_DOOR(typ) || IS_WALL(typ) ||
		   typ == SDOOR || typ == SCORR) {
		ap_type = M_AP_FURNITURE;
		/*
		 *  If there is a wall to the left that connects to this
		 *  location, then the mimic mimics a horizontal closed door.
		 *  This does not allow doors to be in corners of rooms.
		 */
		if (mx != 0 &&
			(levl[mx-1][my].typ == HWALL    ||
			 levl[mx-1][my].typ == TLCORNER ||
			 levl[mx-1][my].typ == TRWALL   ||
			 levl[mx-1][my].typ == BLCORNER ||
			 levl[mx-1][my].typ == TDWALL   ||
			 levl[mx-1][my].typ == CROSSWALL||
			 levl[mx-1][my].typ == TUWALL    ))
		    appear = S_hcdoor;
		else
		    appear = S_vcdoor;

		if(!mtmp->minvis || See_invisible)
		    block_point(mx,my);	/* vision */
	} else if (level.flags.is_maze_lev && rn2(2)) {
		ap_type = M_AP_OBJECT;
		appear = STATUE;
	} else if (roomno < 0) {
		ap_type = M_AP_OBJECT;
		appear = BOULDER;
		if(!mtmp->minvis || See_invisible)
		    block_point(mx,my);	/* vision */
	} else if (rt == ZOO || rt == VAULT) {
		ap_type = M_AP_OBJECT;
		appear = GOLD_PIECE;
	} else if (rt == DELPHI) {
		if (rn2(2)) {
			ap_type = M_AP_OBJECT;
			appear = STATUE;
		} else {
			ap_type = M_AP_FURNITURE;
			appear = S_fountain;
		}
	} else if (rt == TEMPLE) {
		ap_type = M_AP_FURNITURE;
		appear = S_altar;
	/*
	 * We won't bother with beehives, morgues, barracks, throne rooms
	 * since they shouldn't contain too many mimics anyway...
	 */
	} else if (rt >= SHOPBASE) {
		s_sym = get_shop_item(rt - SHOPBASE);
		if (s_sym < 0) {
			ap_type = M_AP_OBJECT;
			appear = -s_sym;
		} else {
			if (s_sym == RANDOM_CLASS)
				s_sym = syms[rn2((int)sizeof(syms)-2) + 2];
			goto assign_sym;
		}
	} else {
		s_sym = syms[rn2((int)sizeof(syms))];
assign_sym:
		if (s_sym >= MAXOCLASSES) {
			ap_type = M_AP_FURNITURE;
			appear = s_sym == MAXOCLASSES ? S_upstair : S_dnstair;
		} else if (s_sym == GOLD_CLASS) {
			ap_type = M_AP_OBJECT;
			appear = GOLD_PIECE;
		} else {
			ap_type = M_AP_OBJECT;
			if (s_sym == S_MIMIC_DEF) {
				appear = STRANGE_OBJECT;
			} else {
				otmp = mkobj( (char) s_sym, FALSE );
				appear = otmp->otyp;
				/* make sure container contents are free'ed */
				obfree(otmp, (struct obj *) 0);
			}
		}
	}
	mtmp->m_ap_type = ap_type;
	mtmp->mappearance = appear;
}

#endif /* OVLB */

/*makemon.c*/
