ftp.nice.ch/pub/next/games/strategic/NetHack.s.tar.gz#/NetHackSource/src/mondata.c

This is mondata.c in view mode; [Download] [Up]

/*	SCCS Id: @(#)mondata.c	3.0	89/11/21
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"
#include "eshk.h"
#include "epri.h"

/*	These routines provide basic data for any type of monster. */

#ifdef OVL0

boolean
attacktype(ptr, atyp)
	register struct	permonst	*ptr;
	register int atyp;
{
	int	i;

	for(i = 0; i < NATTK; i++)
	    if(ptr->mattk[i].aatyp == atyp) return(TRUE);

	return(FALSE);
}

#endif /* OVL0 */
#ifdef OVLB

boolean
resists_ston(ptr)	/* returns TRUE if monster is petrify resistant */
	register struct permonst *ptr;
{
	return (ptr->mflags1 & (M1_STON_RES | M1_ACID) || dmgtype(ptr, AD_STON));
}

boolean
resists_drli(ptr)	/* returns TRUE if monster is drain-life resistant */

	register struct permonst *ptr;
{
	return(is_undead(ptr) || is_demon(ptr) || is_were(ptr));
}

#endif /* OVLB */
#ifdef OVL0

boolean
ranged_attk(ptr)	/* returns TRUE if monster can attack at range */
	register struct permonst *ptr;
{
	return (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) ||
		attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) ||
		attacktype(ptr, AT_MAGC));
}

#endif /* OVL0 */
#ifdef OVL1

boolean
can_track(ptr)		/* returns TRUE if monster can track well */
	register struct permonst *ptr;
{
#ifdef NAMED_ITEMS
	if(uwep && !strcmp(ONAME(uwep), "Excalibur")) return TRUE;
#endif
	return(haseyes(ptr));
}

#endif /* OVL1 */
#ifdef OVLB

#ifdef POLYSELF
boolean
breakarm(ptr)	/* creature will break out of armor */
	register struct permonst *ptr;
{
	return(bigmonst(ptr) || (ptr->msize > MZ_SMALL && !humanoid(ptr))
#ifdef INFERNO
	       || ptr == &mons[PM_MARILITH]
#endif
	       );
	/* Marilith is about the only case of a monster which is otherwise
	 * humanoid but cannot wear armor (too many arms).  Centaurs would
	 * be another except that they are already accounted for by
	 * bigmonst.
	 */
}

boolean
sliparm(ptr)	/* creature will slide out of armor */
	register struct permonst *ptr;
{
	return(ptr->msize < MZ_LARGE &&
	       (ptr->msize <= MZ_SMALL || ptr == &mons[PM_GHOST]));
}
#endif

#endif /* OVLB */
#ifdef OVL1

boolean
sticks(ptr)	/* creature sticks other creatures it hits */
	register struct permonst *ptr;
{
	return(dmgtype(ptr,AD_STCK) || dmgtype(ptr,AD_WRAP) ||
		attacktype(ptr,AT_HUGS));
}

/* not one hundred percent correct: now a snake may hide under an
 *				    invisible object.
 */
boolean
canseemon(mtmp)
	register struct monst *mtmp;
{
	return((!mtmp->minvis || See_invisible)
		&& (!mtmp->mhide ||
		    (!OBJ_AT(mtmp->mx, mtmp->my) &&
		     levl[mtmp->mx][mtmp->my].gmask == 0))
		&& cansee(mtmp->mx, mtmp->my));
}

boolean
dmgtype(ptr, dtyp)
	register struct	permonst	*ptr;
	register int dtyp;
{
	int	i;

	for(i = 0; i < NATTK; i++)
	    if(ptr->mattk[i].adtyp == dtyp) return TRUE;

	return FALSE;
}

int
monsndx(ptr)		/* return an index into the mons array */
	struct	permonst	*ptr;
{
#ifdef LATTICE_504_BUG
	register int d;
/* no problem - see, pspace IS bounded (and fits in 32 bits!) KL */
const int pspace= sizeof(struct permonst[NUMMONS])/NUMMONS;
#endif
	register int	i;

	if(ptr == &playermon) return(-1);
#ifndef LATTICE_504_BUG
	i = (int)(ptr - &mons[0]);
#else
	d=(int)((int)ptr-(int)&mons[0]);
	i= d/pspace;
#endif
	if(i < 0 || i >= NUMMONS) {    
	    panic("monsndx - could not index monster (%x)", ptr);
	    return FALSE;		/* will not get here */
	}

	return(i);
}

int
name_to_mon(str)
char *str;
{
	/* Be careful.  We must check the entire string in case it was
	 * something such as "ettin zombie corpse".  The calling routine
	 * doesn't know about the "corpse" until the monster name has
	 * already been taken off the front, so we have to be able to
	 * read the name with extraneous stuff such as "corpse" stuck on
	 * the end.
	 * This causes a problem for names which prefix other names such
	 * as "ettin" on "ettin zombie".  In this case we want the _longest_
	 * name which exists.
	 * This also permits plurals created by adding suffixes such as 's'
	 * or 'es'.  Other plurals must still be handled explicitly.
	 */
	register int i;
	register int mntmp = -1;
	register char *s;
	char buf[BUFSZ];
	int len=0;

	Strcpy(buf, str);
	str = buf;
	if (!strncmp(str, "a ", 2)) str += 2;
	else if (!strncmp(str, "an ", 3)) str += 3;

	/* Some irregular plurals */
#ifdef INFERNO
	if (!strncmp(str, "incubi", 6)) return PM_INCUBUS;
	if (!strncmp(str, "succubi", 7)) return PM_SUCCUBUS;
#endif
	if (!strncmp(str, "violet fungi", 12)) return PM_VIOLET_FUNGUS;
	if (!strncmp(str, "homunculi", 9)) return PM_HOMUNCULUS;
	if (!strncmp(str, "baluchitheria", 13)) return PM_BALUCHITHERIUM;
	if (!strncmp(str, "lurkers above", 13)) return PM_LURKER_ABOVE;
	if (!strncmp(str, "cavemen", 7)) return PM_CAVEMAN;
	if (!strncmp(str, "cavewomen", 9)) return PM_CAVEWOMAN;
	if (!strncmp(str, "zruties", 7)) return PM_ZRUTY;
	if (!strncmp(str, "djinn", 5)) return PM_DJINNI;
	for(s=str; *s; s++) {
		if (!strncmp(s, "vortices", 8)) {
			Strcpy(s+4, "ex");
			break;
		}
		/* be careful with "ies"; "priest", "zombies" */
		if (!strncmp(s, "jellies", 7) || !strncmp(s, "mummies", 7)) {
			Strcpy(s+4, "y");
			break;
		}
		if (!strncmp(s, "ves", 3)) {
		/* luckily no monster names end in fe or ve with ves plurals */
			Strcpy(s, "f");
			break;
		}
	}
	
	for(i = 0; mons[i].mlet; i++) {
		if(!strncmp(mons[i].mname, str, strlen(mons[i].mname))) {
			if (strlen(mons[i].mname) > len) {
				mntmp = i;
				len = strlen(mons[i].mname);
			}
		}
	}
	return mntmp;
}

#endif /* OVL1 */
#ifdef OVLB

#ifdef POLYSELF
boolean
webmaker(ptr)   /* creature can spin a web */
	register struct permonst *ptr;
{
	return (ptr->mlet == S_SPIDER && ptr != &mons[PM_SCORPION]);
}
#endif

boolean
is_female(mtmp)
	register struct monst *mtmp;
{
	if (mtmp->isshk) return !ESHK(mtmp)->ismale;
#if defined(ALTARS) && defined(THEOLOGY)
	if (mtmp->ispriest) return !EPRI(mtmp)->ismale;
#endif
	return !!(mtmp->data->mflags2 & M2_FEM);
}

#endif /* OVLB */
#ifdef OVL2

/* Gender function.  Differs from is_female() in that 1) It allows the monster
 * type of a polymorphed shopkeeper to override ESHK(mtmp)->ismale, and 2)
 * it returns 3 values (0=male, 1=female, 2=none) instead of 2.
 */
int
gender(mtmp)
	register struct monst *mtmp;
{
	if (!humanoid(mtmp->data)) return 2;
	if (mtmp->data->mflags2 & M2_FEM) return 1;
	if (mtmp->data == &mons[PM_CAVEMAN]
		|| mtmp->data == &mons[PM_PRIEST]
#ifdef INFERNO
		|| mtmp->data == &mons[PM_INCUBUS]
#endif
						) return 0;
#if defined(ALTARS) && defined(THEOLOGY)
	if (mtmp->ispriest) return !EPRI(mtmp)->ismale;
#endif
	if (mtmp->isshk) return !ESHK(mtmp)->ismale;
	return 0;
}

#endif /* OVL2 */
#ifdef OVLB

boolean
levl_follower(mtmp)
register struct monst *mtmp;
{
	return (mtmp->mtame || (mtmp->data->mflags2 & M2_STALK) || is_fshk(mtmp)
		|| (mtmp->iswiz && !mon_has_amulet(mtmp)));
}

struct permonst *
player_mon()
{
	switch (pl_character[0]) {
		case 'A': return &mons[PM_ARCHEOLOGIST];
		case 'B': return &mons[PM_BARBARIAN];
		case 'C': if (flags.female) return &mons[PM_CAVEWOMAN];
			else return &mons[PM_CAVEMAN];
		case 'E': return &mons[PM_ELF];
		case 'H': return &mons[PM_HEALER];
		case 'K': return &mons[PM_KNIGHT];
		case 'P': if (flags.female) return &mons[PM_PRIESTESS];
			else return &mons[PM_PRIEST];
		case 'R': return &mons[PM_ROGUE];
		case 'S': return &mons[PM_SAMURAI];
		case 'T': return &mons[PM_TOURIST];
		case 'V': return &mons[PM_VALKYRIE];
		case 'W': return &mons[PM_WIZARD];
		default: impossible("what are you?");
			return &mons[PM_HUMAN];
	}
}

const int grownups[][2] = { {PM_LITTLE_DOG, PM_DOG}, {PM_DOG, PM_LARGE_DOG},
	{PM_HELL_HOUND_PUP, PM_HELL_HOUND}, {PM_KITTEN, PM_HOUSECAT},
	{PM_HOUSECAT, PM_LARGE_CAT}, {PM_BABY_GRAY_DRAGON, PM_GRAY_DRAGON},
	{PM_KOBOLD, PM_LARGE_KOBOLD}, {PM_LARGE_KOBOLD, PM_KOBOLD_LORD},
	{PM_GNOME, PM_GNOME_LORD}, {PM_GNOME_LORD, PM_GNOME_KING},
	{PM_DWARF, PM_DWARF_LORD}, {PM_DWARF_LORD, PM_DWARF_KING},
	{PM_SMALL_MIMIC, PM_LARGE_MIMIC}, {PM_LARGE_MIMIC, PM_GIANT_MIMIC},
	{PM_BAT, PM_GIANT_BAT},
	{PM_LICH, PM_DEMILICH}, {PM_DEMILICH, PM_MASTER_LICH},
	{PM_OGRE, PM_OGRE_LORD}, {PM_OGRE_LORD, PM_OGRE_KING},
	{PM_VAMPIRE, PM_VAMPIRE_LORD},
	{PM_BABY_RED_DRAGON, PM_RED_DRAGON},
	{PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON},
	{PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON},
	{PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON},
	{PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON},
	{PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON},
	{PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON},
	{PM_RED_NAGA_HATCHLING, PM_RED_NAGA},
	{PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA},
	{PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA},
	{PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA},
	{PM_BABY_PURPLE_WORM, PM_PURPLE_WORM},
#ifdef WORM
	{PM_BABY_LONG_WORM, PM_LONG_WORM},
#endif
#ifdef ARMY
	{PM_SOLDIER, PM_SERGEANT},
	{PM_SERGEANT, PM_LIEUTENANT},
	{PM_LIEUTENANT, PM_CAPTAIN},
#endif
	{PM_BABY_CROCODILE, PM_CROCODILE},
	{-1,-1}
};

int little_to_big(montype)
int montype;
{
	register int i;
	
	for(i=0; grownups[i][0] >= 0; i++)
		if(montype == grownups[i][0]) return grownups[i][1];
	return montype;
}

int big_to_little(montype)
int montype;
{
	register int i;
	
	for(i=0; grownups[i][0] >= 0; i++)
		if(montype == grownups[i][1]) return grownups[i][0];
	return montype;
}


const char *
locomotion(ptr, def)
const struct permonst *ptr;
const char *def;
{
	return (
		is_floater(ptr) ? "float" :
		is_flyer(ptr) ? "fly" :
		slithy(ptr) ? "slither" :
		amorphous(ptr) ? "ooze" :
		nolimbs(ptr) ? "crawl" :
		def
	       );

}

#ifdef STUPID_CPP	/* otherwise these functions are macros in mondata.h */

int
bigmonst(ptr) struct permonst *ptr; {
	return(ptr->msize >= MZ_LARGE);
}

int
verysmall(ptr) struct permonst *ptr; {
	return(ptr->msize < MZ_SMALL);
}

int
is_flyer(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_FLY) != 0L);
}

int
is_floater(ptr) struct permonst *ptr; {
	return(ptr->mlet == S_EYE);
}

int
is_swimmer(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_SWIM) != 0L);
}

int
passes_walls(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_WALLWALK) != 0L);
}

int
noncorporeal(ptr) struct permonst *ptr; {
	return(ptr->mlet == S_GHOST);
}

int
amorphous(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_AMORPHOUS) != 0L);
}

int
tunnels(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_TUNNEL) != 0L);
}

int
needspick(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_NEEDPICK) != 0L);
}

int
hides_under(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_CONCEAL) != 0L);
}

int
is_hider(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_HIDE) != 0L);
}

int
haseyes(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_NOEYES) == 0L);
}

int
nohands(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_NOHANDS) != 0L);
}

int
nolimbs(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_NOLIMBS) == M1_NOLIMBS);
}

# ifdef POLYSELF
int
polyok(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_NOPOLY) == 0L);
}
# endif

int
is_whirly(ptr) struct permonst *ptr; {
	return((ptr->mlet == S_VORTEX) || 
	       (ptr == &mons[PM_AIR_ELEMENTAL]));
}

int
humanoid(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_HUMANOID) != 0L);
}

int
is_animal(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_ANIMAL) != 0L);
}

int
slithy(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_SLITHY) != 0L);
}

int
thick_skinned(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_THICK_HIDE) != 0L);
}

int
resists_fire(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_FIRE_RES) != 0L);
}

int
resists_sleep(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_SLEE_RES) != 0L || is_undead(ptr));
}

int
resists_cold(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_COLD_RES) != 0L);
}

int
resists_disint(ptr) struct permonst *ptr; {
	return(ptr == &mons[PM_BLACK_DRAGON] ||
		ptr == &mons[PM_BABY_BLACK_DRAGON]);
}

int
resists_elec(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_ELEC_RES) != 0L);
}

int
resists_acid(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_ACID) != 0L);
}

int
acidic(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_ACID) != 0L);
}

int
resists_poison(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & (M1_POIS | M1_POIS_RES)) != 0L);
}

int
poisonous(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_POIS) != 0L);
}

int
regenerates(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_REGEN) != 0L);
}

int
perceives(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_SEE_INVIS) != 0L);
}

int
can_teleport(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_TPORT) != 0L);
}

int
control_teleport(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_TPORT_CONTROL) != 0L);
}

int
is_armed(ptr) struct permonst *ptr; {
	return(attacktype(ptr, AT_WEAP));
}

int
likes_gold(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_GREEDY) != 0L);
}

int
likes_gems(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_JEWELS) != 0L);
}

int
likes_objs(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_COLLECT) != 0L || is_armed(ptr));
}

int
likes_magic(ptr) struct permonst *ptr; {
	return((ptr->mflags1 & M1_MAGIC) != 0L);
}

int
is_undead(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_UNDEAD) != 0L);
}

int
is_were(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_WERE) != 0L);
}

int
is_elf(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_ELF) != 0L);
}

int
is_dwarf(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_DWARF) != 0L);
}

int
is_giant(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_GIANT) != 0L);
}

# ifdef GOLEMS
int
is_golem(ptr) struct permonst *ptr; {
	return(ptr->mlet == S_GOLEM);
}
# endif /* GOLEMS */

int
is_domestic(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_DOMESTIC) != 0L);
}


int
is_orc(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_ORC) != 0L);
}

int
is_human(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_HUMAN) != 0L);
}

int
is_demon(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_DEMON) != 0L);
}

int
is_mercenary(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_MERC) != 0L);
}

int
is_wanderer(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_WANDER) != 0L);
}

int
always_hostile(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_HOSTILE) != 0L);
}

int
always_peaceful(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_PEACEFUL) != 0L);
}

int
extra_nasty(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_NASTY) != 0L);
}

int
strongmonst(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_STRONG) != 0L);
}

# ifdef POLYSELF
int
can_breathe(ptr) struct permonst *ptr; {
	return(attacktype(ptr, AT_BREA));
}

int
cantwield(ptr) struct permonst *ptr; {
	return(nohands(ptr) || verysmall(ptr));
}

int
cantweararm(ptr) struct permonst *ptr; {
	return(breakarm(ptr) || sliparm(ptr));
}
# endif /* POLYSELF */

int
carnivorous(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_CARNIVORE) != 0L);
}

int
herbivorous(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_HERBIVORE) != 0L);
}

int
metallivorous(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_METALLIVORE) != 0L);
}

int
lays_eggs(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_EGGS) != 0L);
}

int
throws_rocks(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_ROCKTHROW) != 0L);
}

int
type_is_pname(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_PNAME) != 0L);
}

int
is_lord(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_LORD) != 0L);
}

int
is_prince(ptr) struct permonst *ptr; {
	return((ptr->mflags2 & M2_PRINCE) != 0L);
}

# ifdef INFERNO
int
is_ndemon(ptr) struct permonst *ptr; {
	return(is_demon(ptr) &&
		(ptr->mflags2 & (M2_LORD | M2_PRINCE)) == 0L);
}
# else
int
is_ndemon(ptr) struct permonst *ptr; {
	return(ptr == &mons[PM_DEMON]);
}
# endif

int
is_dlord(ptr) struct permonst *ptr; {
	return(is_demon(ptr) && is_lord(ptr));
}

int
is_dprince(ptr) struct permonst *ptr; {
	return(is_demon(ptr) && is_prince(ptr));
}

#endif /* STUPID_CPP */

#endif /* OVLB */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.