home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume10
/
nethack3p9
/
part17
< prev
next >
Wrap
Internet Message Format
|
1990-07-12
|
60KB
Path: uunet!samsung!zaphod.mps.ohio-state.edu!wuarchive!mit-eddie!uw-beaver!zephyr.ens.tek.com!tekred!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v10i062: nethack3p9 - display oriented dungeons & dragons (Ver. 3.0i), Part17/56
Message-ID: <5918@tekred.CNA.TEK.COM>
Date: 12 Jul 90 00:35:18 GMT
Sender: news@tekred.CNA.TEK.COM
Lines: 2208
Approved: billr@saab.CNA.TEK.COM
Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 10, Issue 62
Archive-name: nethack3p9/Part17
Supersedes: NetHack3: Volume 7, Issue 56-93
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 17 (of 56)."
# Contents: src/mhitm.c src/mon.c
# Wrapped by billr@saab on Wed Jul 11 17:11:14 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/mhitm.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/mhitm.c'\"
else
echo shar: Extracting \"'src/mhitm.c'\" \(19029 characters\)
sed "s/^X//" >'src/mhitm.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)mhitm.c 3.0 89/11/27
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X#ifdef NAMED_ITEMS
X# include "artifact.h"
X#endif
X
X#ifdef OVLB
X
Xstatic boolean NEARDATA vis, NEARDATA far_noise;
Xstatic long NEARDATA noisetime;
Xstatic struct obj NEARDATA *otmp;
X
Xstatic void FDECL(mrustm, (struct monst *, struct monst *, struct obj *));
Xstatic int FDECL(hitmm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(gazemm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(explmm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *));
Xstatic void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
Xstatic void FDECL(noises,(struct monst *,struct attack *));
Xstatic void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
X
Xstatic void
Xnoises(magr, mattk)
X register struct monst *magr;
X register struct attack *mattk;
X{
X boolean farq = (dist(magr->mx, magr->my) > 15);
X
X if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) {
X far_noise = farq;
X noisetime = moves;
X You("hear %s%s.",
X (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
X farq ? " in the distance" : "");
X }
X}
X
Xstatic
Xvoid
Xmissmm(magr, mdef, mattk)
X register struct monst *magr, *mdef;
X struct attack *mattk;
X{
X char buf[BUFSZ];
X
X if(vis) {
X if(mdef->mimic) seemimic(mdef);
X if(magr->mimic) seemimic(magr);
X if (could_seduce(magr,mdef,mattk) && !magr->mcan)
X Sprintf(buf, "%s pretends to be friendly to",
X Monnam(magr));
X else
X Sprintf(buf,"%s misses", Monnam(magr));
X pline("%s %s.", buf, mon_nam(mdef));
X } else noises(magr, mattk);
X}
X
X/*
X * fightm returns 3 if no attack, otherwise the results of mattackm
X */
Xint
Xfightm(mtmp) /* have monsters fight each other */
X register struct monst *mtmp;
X{
Xregister struct monst *mon, *nmon;
X#ifdef LINT
X nmon = 0;
X#endif
X for(mon = fmon; mon; mon = nmon) {
X nmon = mon->nmon;
X if(nmon == mtmp) nmon = mtmp->nmon;
X if(mon != mtmp) {
X if(dist2(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3)
X /* note: grid bug check needed here as well as in mattackm */
X if(mtmp->data != &mons[PM_GRID_BUG] || mtmp->mx==mon->mx
X || mtmp->my==mon->my)
X return(mattackm(mtmp,mon));
X }
X }
X return(3);
X}
X
X/*
X * mattackm returns -1 (magr died), 0 (miss), 1 (mdef hit), or 2 (mdef killed)
X *
X * Each successive attack has a lower probability of hitting. Some
X * rely on the success of previous attacks.
X *
X * In the case of exploding monsters, the monster dies as well.
X */
Xint
Xmattackm(magr, mdef)
X register struct monst *magr,*mdef;
X{
X int i, tmp, nsum, sum[NATTK];
X struct attack *mattk;
X struct permonst *pa, *pd;
X schar strike;
X
X if(!magr || !mdef) return(0); /* mike@genat */
X pa = magr->data; pd = mdef->data;
X if(!magr->mcanmove) return(0); /* riv05!a3 */
X if(pa==&mons[PM_GRID_BUG] && magr->mx != mdef->mx
X && magr->my != mdef->my)
X return(0);
X
X/* Calculate the armour class differential. */
X
X tmp = pd->ac + magr->m_lev;
X if(mdef->mconf || !mdef->mcanmove || mdef->msleep){
X tmp += 4;
X if(mdef->msleep) mdef->msleep = 0;
X }
X
X if (is_elf(magr->data) && is_orc(mdef->data)) tmp++;
X
X/* Set up visibility of action */
X vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my));
X
X/* Set flag indicating monster has moved this turn. Necessary since a
X * monster might get an attack out of sequence (i.e. before its move) in
X * some cases, in which case this still counts as its move for the round
X * and it shouldn't move again.
X */
X magr->mlstmv = moves;
X
X/* Now perform all attacks for the monster. */
X
X for(i=0; i<NATTK; i++) sum[i] = 0;
X for(i = nsum = 0; i < NATTK; nsum |= sum[i++]) {
X mattk = &(pa->mattk[i]);
X otmp = (struct obj *)0;
X switch(mattk->aatyp) {
X
X case AT_WEAP: /* "hand to hand" attacks */
X otmp = select_hwep(magr);
X if(otmp) {
X if (vis) mswingsm(magr, mdef, otmp);
X tmp += hitval(otmp, pd);
X }
X case AT_CLAW:
X case AT_KICK:
X case AT_BITE:
X case AT_STNG:
X case AT_TUCH:
X case AT_BUTT:
X if((strike = (tmp > rnd(20+i)))) {
X sum[i] = hitmm(magr, mdef, mattk);
X if(sum[i] == -1) return(-1);
X } else missmm(magr, mdef, mattk);
X break;
X
X case AT_HUGS: /* automatic if prev two attacks succeed */
X strike = 1;
X if(sum[i-1] && sum[i-2]) {
X sum[i] = hitmm(magr, mdef, mattk);
X if(sum[i] == -1) return(-1);
X }
X break;
X
X case AT_GAZE: /* will not wake up a sleeper */
X strike = 0;
X sum[i] = gazemm(magr, mdef, mattk);
X break;
X
X case AT_EXPL: /* automatic hit if next to */
X strike = -1;
X sum[i] = explmm(magr, mdef, mattk);
X break;
X
X case AT_ENGL:
X if((strike = (tmp > rnd(20+i))))
X sum[i]= gulpmm(magr, mdef, mattk);
X else missmm(magr, mdef, mattk);
X break;
X
X default: /* no attack */
X strike = 0;
X break;
X }
X if(sum[i] == 2) return(2); /* defender dead */
X if(strike) mdef->msleep = 0;
X if(strike == -1) return(-1); /* attacker dead */
X nsum |= sum[i];
X }
X return(nsum);
X}
X
X/* hitmm returns 0 (miss), 1 (hit), 2 (kill), or -1 (magr died) */
Xstatic int
Xhitmm(magr, mdef, mattk)
X register struct monst *magr,*mdef;
X struct attack *mattk;
X{
X if(vis){
X int compat;
X char buf[BUFSZ];
X
X if(mdef->mimic) seemimic(mdef);
X if(magr->mimic) seemimic(magr);
X if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) {
X Sprintf(buf, "%s %s", Monnam(magr),
X mdef->mcansee ? "smiles at" : "talks to");
X pline("%s %s %s.", buf, mon_nam(mdef),
X compat == 2 ?
X "engagingly" : "seductively");
X } else {
X switch (mattk->aatyp) {
X case AT_BITE:
X Sprintf(buf,"%s bites", Monnam(magr));
X break;
X case AT_STNG:
X Sprintf(buf,"%s stings", Monnam(magr));
X break;
X case AT_BUTT:
X Sprintf(buf,"%s butts", Monnam(magr));
X break;
X case AT_TUCH:
X Sprintf(buf,"%s touches", Monnam(magr));
X break;
X case AT_HUGS:
X if (magr != u.ustuck) {
X Sprintf(buf,"%s squeezes", Monnam(magr));
X break;
X }
X default:
X Sprintf(buf,"%s hits", Monnam(magr));
X }
X }
X pline("%s %s.", buf, mon_nam(mdef));
X } else noises(magr, mattk);
X return(mdamagem(magr, mdef, mattk));
X}
X
Xstatic int
Xgazemm(magr, mdef, mattk)
X register struct monst *magr, *mdef;
X struct attack *mattk;
X{
X char buf[BUFSZ];
X
X if(vis) {
X Sprintf(buf,"%s gazes at", Monnam(magr));
X pline("%s %s.", buf, mon_nam(mdef));
X }
X
X if (!mdef->mcansee || mdef->msleep) {
X
X if(vis) pline("but nothing happens.");
X return(0);
X }
X
X return(mdamagem(magr, mdef, mattk));
X}
X
Xstatic int
Xgulpmm(magr, mdef, mattk)
X register struct monst *magr, *mdef;
X register struct attack *mattk;
X{
X int mx, my, tmp;
X char buf[BUFSZ];
X
X if(mdef->data->msize >= MZ_HUGE) return 0;
X
X if(vis) {
X Sprintf(buf,"%s swallows", Monnam(magr));
X pline("%s %s.", buf, mon_nam(mdef));
X }
X
X mx = magr->mx;
X my = magr->my;
X /* move over top of the defender */
X if(cansee(mdef->mx, mdef->my)) unpmon(mdef);
X if(cansee(magr->mx, magr->my)) unpmon(magr);
X magr->mx = mdef->mx;
X magr->my = mdef->my;
X if(cansee(magr->mx, magr->my)) pmon(magr);
X if((tmp = mdamagem(magr, mdef, mattk)) == 2) {
X remove_monster(mx, my);
X place_monster(magr, magr->mx, magr->my);
X /* if mdamagem left a corpse it erased magr's symbol */
X unpmon(magr);
X pmon(magr);
X return(2); /* defender died */
X } else { /* defender survived */
X if(cansee(mdef->mx, mdef->my))
X pline("%s is regurgitated!", Monnam(mdef));
X if(cansee(magr->mx, magr->my)) unpmon(magr);
X magr->mx = mx;
X magr->my = my;
X /* move off of defender */
X if(cansee(magr->mx, magr->my)) pmon(magr);
X if(cansee(mdef->mx, mdef->my)) pmon(mdef);
X nscr();
X return(tmp);
X }
X}
X
Xstatic int
Xexplmm(magr, mdef, mattk)
X register struct monst *magr, *mdef;
X register struct attack *mattk;
X{
X
X if(cansee(magr->mx, magr->my))
X pline("%s explodes!", Monnam(magr));
X else noises(magr, mattk);
X
X (void) mdamagem(magr, mdef, mattk);
X
X if(magr->mtame)
X You("have a sad feeling for a moment, then it passes.");
X mondead(magr);
X return(2);
X}
X
Xstatic const char psf[] =
X "have a peculiarly sad feeling for a moment, then it passes.";
X
Xstatic int
Xmdamagem(magr, mdef, mattk)
X register struct monst *magr, *mdef;
X register struct attack *mattk;
X{
X struct permonst *ptr, *pd = mdef->data;
X int tmp = d((int)mattk->damn,(int)mattk->damd);
X char buf[BUFSZ];
X
X if(mdef->data == &mons[PM_COCKATRICE] && !resists_ston(magr->data) &&
X (mattk->aatyp != AT_WEAP || !otmp) &&
X (mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL) &&
X (!is_mercenary(magr->data) || !m_carrying(magr, LEATHER_GLOVES))) {
X /* Note: other monsters may carry gloves, only soldiers have them */
X /* as their "armor" and can be said to wear them */
X if (vis) pline("%s turns to stone!", Monnam(magr));
X else if (magr->mtame) You(psf);
X monstone(magr);
X return -1;
X }
X
X switch(mattk->adtyp) {
X case AD_DGST:
X if(flags.verbose && flags.soundok) verbalize("Burrrrp!");
X tmp = mdef->mhp;
X break;
X case AD_STUN:
X if (magr->mcan) break;
X if(vis) pline("%s staggers for a moment.", Monnam(mdef));
X mdef->mstun = 1;
X /* fall through */
X case AD_WERE:
X case AD_HEAL:
X case AD_LEGS:
X case AD_PHYS:
X if (mattk->aatyp == AT_KICK && thick_skinned(mdef->data))
X tmp = 0;
X else if(mattk->aatyp == AT_WEAP) {
X if(otmp) {
X tmp += dmgval(otmp, pd);
X#ifdef NAMED_ITEMS
X if(spec_ability(otmp, SPFX_DRLI) &&
X !resists_drli(mdef->data)) {
X int dam = rnd(8);
X
X tmp += dam;
X if(vis)
X pline("The %s blade drains the life from %s!",
X Hallucination ? hcolor() : black,
X mon_nam(mdef));
X mdef->mhpmax -= dam;
X if (mdef->m_lev == 0)
X tmp = mdef->mhp;
X else mdef->m_lev--;
X }
X#endif
X mrustm(magr, mdef, otmp);
X }
X }
X break;
X case AD_FIRE:
X if (magr->mcan) {
X tmp = 0;
X break;
X }
X if(vis) pline("%s is on fire!", Monnam(mdef));
X tmp += destroy_mitem(mdef, SCROLL_SYM, AD_FIRE);
X#ifdef SPELLS
X tmp += destroy_mitem(mdef, SPBOOK_SYM, AD_FIRE);
X#endif
X if(resists_fire(pd)) {
X pline("The fire doesn't seem to burn %s!", mon_nam(mdef));
X shieldeff(mdef->mx, mdef->my);
X#ifdef GOLEMS
X golemeffects(mdef, AD_FIRE, tmp);
X#endif /* GOLEMS */
X tmp = 0;
X }
X /* only potions damage resistant players in destroy_item */
X tmp += destroy_mitem(mdef, POTION_SYM, AD_FIRE);
X break;
X case AD_COLD:
X if (magr->mcan) {
X tmp = 0;
X break;
X }
X if(vis) pline("%s is covered in frost!", Monnam(mdef));
X if(resists_cold(pd)) {
X pline("The frost doesn't seem to chill %s!",
X mon_nam(mdef));
X shieldeff(mdef->mx, mdef->my);
X#ifdef GOLEMS
X golemeffects(mdef, AD_COLD, tmp);
X#endif /* GOLEMS */
X tmp = 0;
X }
X tmp += destroy_mitem(mdef, POTION_SYM, AD_COLD);
X break;
X case AD_ELEC:
X if (magr->mcan) {
X tmp = 0;
X break;
X }
X if(vis) pline("%s gets zapped!", Monnam(mdef));
X tmp += destroy_mitem(mdef, WAND_SYM, AD_ELEC);
X if(resists_elec(pd)) {
X pline("The zap doesn't shock %s!", mon_nam(mdef));
X shieldeff(mdef->mx, mdef->my);
X#ifdef GOLEMS
X golemeffects(mdef, AD_ELEC, tmp);
X#endif /* GOLEMS */
X tmp = 0;
X }
X /* only rings damage resistant players in destroy_item */
X tmp += destroy_mitem(mdef, RING_SYM, AD_ELEC);
X break;
X case AD_ACID:
X if (magr->mcan) {
X tmp = 0;
X break;
X }
X if(resists_acid(pd)) {
X pline("%s is covered in acid, but it seems harmless.",
X Monnam(mdef));
X tmp = 0;
X } else {
X pline("%s is covered in acid!", Monnam(mdef));
X pline("It burns %s!", mon_nam(mdef));
X }
X break;
X case AD_RUST:
X#ifdef GOLEMS
X if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) {
X if (vis) pline("%s falls to pieces!", Monnam(mdef));
X else if(mdef->mtame)
X pline("May %s rust in peace.", mon_nam(mdef));
X mondied(mdef);
X magr->mhpmax = magr->mhpmax +
X (1 + rn2((int)mdef->m_lev+1));
X ptr = grow_up(magr);
X if(!ptr) return(-1);
X return(2);
X }
X#endif /* GOLEMS */
X tmp = 0;
X break;
X case AD_DCAY:
X#ifdef GOLEMS
X if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] ||
X pd == &mons[PM_LEATHER_GOLEM])) {
X if (vis) pline("%s falls to pieces!", Monnam(mdef));
X else if(mdef->mtame)
X pline("May %s rot in peace.", mon_nam(mdef));
X mondied(mdef);
X magr->mhpmax = magr->mhpmax +
X (1 + rn2((int)mdef->m_lev+1));
X ptr = grow_up(magr);
X if(!ptr) return(-1);
X return(2);
X }
X#endif /* GOLEMS */
X tmp = 0;
X break;
X case AD_STON:
X if(!resists_ston(pd)) {
X magr->mhpmax = magr->mhpmax +
X (1 + rn2((int)mdef->m_lev+1));
X if(vis) pline("%s turns to stone!", Monnam(mdef));
X else if(mdef->mtame) You(psf);
X monstone(mdef);
X ptr = grow_up(magr);
X if(!ptr) return(-1);
X return(2);
X }
X tmp = 0; /* no damage if this fails */
X break;
X case AD_TLPT:
X if(!magr->mcan && tmp < mdef->mhp) {
X rloc(mdef);
X if(vis && !cansee(mdef->mx, mdef->my))
X pline("%s suddenly disappears!", Monnam(mdef));
X }
X break;
X case AD_SLEE:
X if(!resists_sleep(pd) && !magr->mcan && !mdef->msleep
X && mdef->mcanmove) {
X if (vis) {
X Strcpy(buf, Monnam(mdef));
X pline("%s is put to sleep by %s.", buf, mon_nam(magr));
X }
X mdef->mcanmove = 0;
X mdef->mfrozen = rnd(10);
X }
X break;
X case AD_PLYS:
X if(!magr->mcan && mdef->mcanmove) {
X if (vis) {
X Strcpy(buf, Monnam(mdef));
X pline("%s is frozen by %s.", buf, mon_nam(magr));
X }
X mdef->mcanmove = 0;
X mdef->mfrozen = rnd(10);
X }
X break;
X case AD_SLOW:
X if(!magr->mcan && vis && mdef->mspeed != MSLOW) {
X if (vis) pline("%s slows down.", Monnam(mdef));
X if (mdef->mspeed == MFAST) mdef->mspeed = 0;
X else mdef->mspeed = MSLOW;
X }
X break;
X case AD_CONF:
X /* Since confusing another monster doesn't have a real time
X * limit, setting spec_used would not really be right (though
X * we still should check for it).
X */
X if(!magr->mcan && vis && !mdef->mconf && !magr->mspec_used) {
X pline("%s looks confused.", Monnam(mdef));
X mdef->mconf = 1;
X }
X break;
X case AD_BLND:
X if(!magr->mcan && haseyes(pd)) {
X
X if(vis && mdef->mcansee)
X pline("%s is blinded.", Monnam(mdef));
X {
X register unsigned rnd_tmp;
X rnd_tmp = d((int)mattk->damn, (int)mattk->damd);
X mdef->mcansee = 0;
X if((mdef->mblinded + rnd_tmp) > 127)
X mdef->mblinded = 127;
X else mdef->mblinded += rnd_tmp;
X }
X }
X tmp = 0;
X break;
X case AD_CURS:
X if(!night() && (magr->data == &mons[PM_GREMLIN])) break;
X if(!magr->mcan && !rn2(10)) {
X if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
X were_change(mdef);
X#ifdef GOLEMS
X if (mdef->data == &mons[PM_CLAY_GOLEM]) {
X if (vis) {
X pline("Some writing vanishes from %s's head!",
X mon_nam(mdef));
X pline("%s dies!", Monnam(mdef));
X }
X else if (mdef->mtame)
X You("have a strangely sad feeling for a moment, then it passes.");
X mondied(mdef);
X magr->mhpmax = magr->mhpmax +
X (1 + rn2((int)mdef->m_lev+1));
X ptr = grow_up(magr);
X if(!ptr) return(-1);
X return(2);
X }
X#endif /* GOLEMS */
X mdef->mcan = 1;
X if (flags.soundok) {
X if (!vis) You("hear laughter.");
X else pline("%s chuckles.", Monnam(magr));
X }
X }
X break;
X case AD_SGLD:
X tmp = 0;
X if (magr->mcan || !mdef->mgold) break;
X /* technically incorrect; no check for stealing gold from
X * between mdef's feet...
X */
X magr->mgold += mdef->mgold;
X mdef->mgold = 0;
X if (vis) {
X Strcpy(buf, Monnam(magr));
X pline("%s steals some gold from %s.", buf,
X mon_nam(mdef));
X }
X break;
X case AD_DRLI:
X if(rn2(2) && !resists_drli(mdef->data)) {
X tmp = d(2,6);
X if (vis)
X kludge("%s suddenly seems weaker!", Monnam(mdef));
X mdef->mhpmax -= tmp;
X if (mdef->m_lev == 0)
X tmp = mdef->mhp;
X else mdef->m_lev--;
X /* Automatic kill if drained past level 0 */
X }
X break;
X#ifdef SEDUCE
X case AD_SSEX:
X#endif
X case AD_SITM: /* for now these are the same */
X case AD_SEDU:
X if (!magr->mcan && mdef->minvent) {
X otmp = mdef->minvent;
X mdef->minvent = otmp->nobj;
X otmp->nobj = magr->minvent;
X magr->minvent = otmp;
X if (vis) {
X Strcpy(buf, Monnam(magr));
X pline("%s steals %s from %s!", buf,
X doname(otmp), mon_nam(mdef));
X }
X }
X tmp = 0;
X break;
X case AD_DRST:
X case AD_DRDX:
X case AD_DRCO:
X if (!magr->mcan && !rn2(8)) {
X if (vis)
X pline("%s's %s was poisoned!", Monnam(magr),
X mattk->aatyp==AT_BITE ? "bite" : "sting");
X if (resists_poison(mdef->data)) {
X if (vis)
X pline("The poison doesn't seem to affect %s.",
X mon_nam(mdef));
X } else {
X if (rn2(10)) tmp += rn1(10,6);
X else {
X if (vis) pline("The poison was deadly...");
X tmp = mdef->mhp;
X }
X }
X }
X break;
X case AD_STCK:
X case AD_WRAP: /* monsters cannot grab one another, it's too hard */
X break;
X default: tmp = 0;
X break;
X }
X if(!tmp) return(1);
X
X if((mdef->mhp -= tmp) < 1) {
X magr->mhpmax = magr->mhpmax + (1 + rn2((int)mdef->m_lev+1));
X if(vis)
X pline("%s is %s!", Monnam(mdef),
X (is_demon(mdef->data) || is_undead(mdef->data)) ?
X "destroyed" : "killed");
X else if(mdef->mtame)
X You("have a sad feeling for a moment, then it passes.");
X mondied(mdef);
X ptr = grow_up(magr);
X if(!ptr) return(-1);
X return(2);
X }
X return(1);
X}
X
X#endif /* OVLB */
X#ifdef OVL0
X
Xint
Xnoattacks(ptr) /* returns 1 if monster doesn't attack */
X struct permonst *ptr;
X{
X int i;
X
X for(i = 0; i < NATTK; i++)
X if(ptr->mattk[i].aatyp) return(0);
X
X return(1);
X}
X
X#endif /* OVL0 */
X#ifdef OVLB
X
Xstatic void
Xmrustm(magr, mdef, obj)
Xregister struct monst *magr, *mdef;
Xregister struct obj *obj;
X{
X if (!magr || !mdef || !obj) return; /* just in case */
X if (mdef->data == &mons[PM_RUST_MONSTER] &&
X objects[obj->otyp].oc_material == METAL &&
X !obj->rustfree && obj->spe > -2) {
X if(obj->blessed && rn2(3)) {
X if (cansee(mdef->mx, mdef->my))
X pline("%s's weapon is not affected.", Monnam(magr));
X } else {
X if (cansee(mdef->mx, mdef->my))
X pline("%s's %s!", Monnam(magr),
X aobjnam(obj, "corrode"));
X obj->spe--;
X }
X }
X}
X
Xstatic void
Xmswingsm(magr, mdef, otemp)
Xregister struct monst *magr, *mdef;
Xregister struct obj *otemp;
X{
X char buf[BUFSZ];
X Strcpy(buf, mon_nam(mdef));
X if (!flags.verbose || Blind || otemp->olet != WEAPON_SYM) return;
X pline("%s %s %s %s at %s.", Monnam(magr),
X ((otemp->otyp >= SPEAR &&
X otemp->otyp <= LANCE) ||
X (otemp->otyp >= PARTISAN &&
X otemp->otyp <= SPETUM) ||
X otemp->otyp == TRIDENT) ? "thrusts" : "swings",
X is_female(magr) ? "her" :
X is_human(magr->data) ? "his" : "its",
X xname(otemp), buf);
X}
X
X#endif /* OVLB */
END_OF_FILE
if test 19029 -ne `wc -c <'src/mhitm.c'`; then
echo shar: \"'src/mhitm.c'\" unpacked with wrong size!
fi
# end of 'src/mhitm.c'
fi
if test -f 'src/mon.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/mon.c'\"
else
echo shar: Extracting \"'src/mon.c'\" \(36529 characters\)
sed "s/^X//" >'src/mon.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)mon.c 3.0 89/11/22
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X/* Aztec C on amiga doesn't recognize defined() at this point!
X Neither does the Mac Lightspeed C v.3 compiler. If you're using
X precompiled headers, you don't want this either */
X#ifndef AZTEC_C
X#ifndef THINK_C
X#if defined(MICROPORT_BUG) || (!defined(LINT) && !defined(__STDC__))
X#define MKROOM_H
X#endif /* Avoid the microport bug */
X#endif
X#endif
X
X#include "hack.h"
X#include "mfndpos.h"
X
X#ifdef WORM
X# include "wseg.h"
X#endif
X
X#ifdef HARD
XSTATIC_DCL boolean FDECL(restrap,(struct monst *));
X#endif
X#ifdef INFERNO
X# include <ctype.h>
X#endif
X
XSTATIC_DCL void NDECL(dmonsfree);
X
X#ifdef OVL1
Xlong lastwarntime;
Xint lastwarnlev;
Xconst char *warnings[] = {
X "white", "pink", "red", "ruby", "purple", "black" };
X
X#endif /* OVL1 */
X
X#ifdef OVLB
Xstatic struct obj *FDECL(make_corpse,(struct monst *));
Xstatic void FDECL(m_detach,(struct monst *));
X
Xstruct monst *fdmon; /* chain of dead monsters, need not be saved */
X /* otherwise used only in priest.c */
X
X/* Creates a monster corpse, a "special" corpse, or nothing if it doesn't
X * leave corpses. Monsters which leave "special" corpses should have
X * G_NOCORPSE set in order to prevent wishing for one, finding tins of one,
X * etc....
X */
Xstatic struct obj *
Xmake_corpse(mtmp)
Xregister struct monst *mtmp;
X{
X register struct permonst *mdat = mtmp->data;
X#ifdef GOLEMS
X int pieces;
X#endif
X struct obj *obj = 0;
X int x = mtmp->mx, y = mtmp->my;
X
X switch(monsndx(mdat)) {
X case PM_WHITE_UNICORN:
X case PM_GRAY_UNICORN:
X case PM_BLACK_UNICORN:
X (void) mksobj_at(UNICORN_HORN, x, y);
X goto default_1;
X#ifdef WORM
X case PM_LONG_WORM:
X (void) mksobj_at(WORM_TOOTH, x, y);
X goto default_1;
X#endif
X case PM_KOBOLD_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_KOBOLD_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_KOBOLD;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X case PM_GNOME_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_GNOME_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_GNOME;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X case PM_ORC_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_ORC_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_ORC;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X case PM_ELF_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_ELF_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_ELF;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X case PM_HUMAN_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_HUMAN_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_HUMAN;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X case PM_GIANT_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_GIANT_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_GIANT;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X case PM_ETTIN_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_ETTIN_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_ETTIN;
X obj->age -= 50; /* this is an *OLD* corpse */
X break;
X#ifdef GOLEMS
X case PM_IRON_GOLEM:
X pieces = d(2,6);
X while (pieces--)
X obj = mksobj_at(IRON_CHAIN, x, y);
X break;
X case PM_CLAY_GOLEM:
X obj = mksobj_at(ROCK, x, y);
X obj->quan = rn2(20) + 100;
X obj->owt = weight(obj);
X break;
X case PM_STONE_GOLEM:
X obj = mkcorpstat(STATUE, mdat, x, y);
X break;
X case PM_WOOD_GOLEM:
X pieces = d(2,4);
X while(pieces--)
X obj = mksobj_at(QUARTERSTAFF, x, y);
X break;
X case PM_LEATHER_GOLEM:
X pieces = d(2,4);
X while(pieces--)
X obj = mksobj_at(LEATHER_ARMOR, x, y);
X break;
X#endif
X default_1:
X default:
X if (mdat->geno & G_NOCORPSE)
X return (struct obj *)0;
X else obj = mkcorpstat(CORPSE, mdat, x, y);
X break;
X }
X /* All special cases should precede the G_NOCORPSE check */
X
X /* Note: oname() cannot be used generically for non-inventory objects
X * unless you fix the link from the previous object in the chains.
X * (Here we know it's the first one, so there was no link.)
X */
X if (mtmp->mnamelth) {
X obj = oname(obj, NAME(mtmp), 0);
X fobj = obj;
X level.objects[x][y] = obj;
X }
X stackobj(fobj);
X newsym(x, y);
X return obj;
X}
X
X#endif /* OVLB */
X#ifdef OVL2
X
XSTATIC_OVL void
Xdmonsfree(){
Xregister struct monst *mtmp;
X while(mtmp = fdmon){
X fdmon = mtmp->nmon;
X free((genericptr_t) mtmp);
X }
X}
X
X#endif /* OVL2 */
X#ifdef OVL1
X
Xvoid
Xmovemon()
X{
X register struct monst *mtmp;
X
X warnlevel = 0;
X
X while(1) {
X /* Find a monster that we have not treated yet.
X * Note that mtmp or mtmp->nmon might get killed
X * while mtmp moves, so we cannot just walk down the
X * chain (even new monsters might get created!)
X */
X /* Do tame monsters first. Necessary so that when the tame
X * monster attacks something, the something gets a chance to
X * attack the tame monster back (which it's permitted to do
X * only if it hasn't made its move yet).
X */
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->mlstmv < moves && mtmp->mtame) goto next_mon;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->mlstmv < moves && !mtmp->mtame) goto next_mon;
X /* treated all monsters */
X break;
X
X next_mon:
X mtmp->mlstmv = moves;
X
X /* most monsters drown in pools */
X { boolean inpool,iseel,isgremlin;
X#ifdef FOUNTAINS
X boolean infountain;
X#endif
X
X inpool = is_pool(mtmp->mx,mtmp->my);
X iseel = mtmp->data->mlet == S_EEL;
X isgremlin = mtmp->data->mlet == S_GREMLIN;
X#ifdef FOUNTAINS
X infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ);
X#endif
X /* Gremlin multiplying won't go on forever since the hit points
X * keep going down, and when it gets to 1 hit point the clone
X * function will fail.
X */
X if((inpool
X#ifdef FOUNTAINS
X || infountain
X#endif
X ) && isgremlin && rn2(3)) {
X struct monst *mtmp2 = clone_mon(mtmp);
X
X if (mtmp2) {
X mtmp2->mhpmax = (mtmp->mhpmax /= 2);
X if(cansee(mtmp->mx,mtmp->my))
X pline("%s multiplies.", Monnam(mtmp));
X }
X#ifdef FOUNTAINS
X if (infountain) dryup();
X#endif
X } else
X if(inpool && !is_flyer(mtmp->data) && !is_swimmer(mtmp->data)) {
X if(cansee(mtmp->mx,mtmp->my))
X pline("%s drowns.", Monnam(mtmp));
X mondead(mtmp);
X continue;
X } else
X /* but eels have a difficult time outside */
X if(iseel && !inpool) {
X if(mtmp->mhp > 1) mtmp->mhp--;
X mtmp->mflee = 1;
X mtmp->mfleetim += 2;
X }
X }
X if(mtmp->mblinded && !--mtmp->mblinded)
X mtmp->mcansee = 1;
X if(mtmp->mfrozen && !--mtmp->mfrozen)
X mtmp->mcanmove = 1;
X if(mtmp->mfleetim && !--mtmp->mfleetim)
X mtmp->mflee = 0;
X#ifdef HARD
X /* unwatched mimics and piercers may hide again [MRS] */
X if(is_hider(mtmp->data) && restrap(mtmp)) continue;
X#endif
X if(mtmp->mimic) continue;
X if(mtmp->mspeed != MSLOW || !(moves%2)){
X /* continue if the monster died fighting */
X if (Conflict && !mtmp->iswiz && mtmp->mcansee) {
X/* Note: A couple of notes on conflict here.
X 1. Conflict does not take effect in the first round. Therefore,
X A monster in a stepping into the area will get to swing at you.
X 2. Conflict still works when you are invisible. (?)
X 3. Certain areas (namely castle) you can be in 3 "rooms" at once!
X Polyself into Xorn wearing ring of conflict and it can be done.
X This code only allows for two. This needs to be changed if more
X areas (with diggable walls and > 2 rooms) are put into the game.
X*/
X xchar clx = 0, chx = 0, cly = 0, chy = 0,
X clx2 = 0, chx2 = 0, cly2 = 0, chy2 = 0;
X /* seelx etc. are not set if blind or blindfolded! */
X getcorners(&clx, &chx, &cly, &chy,
X &clx2, &chx2, &cly2, &chy2);
X if ((dist(mtmp->mx,mtmp->my) < 3) ||
X /* if the monster is next to you OR */
X (levl[u.ux][u.uy].lit &&
X levl[mtmp->mx][mtmp->my].lit &&
X /* both you and it are lit AND */
X ((clx <= mtmp->mx && mtmp->mx <= chx &&
X cly <= mtmp->my && mtmp->my <= chy) ||
X (clx2 <= mtmp->mx && mtmp->mx <= chx2 &&
X cly2 <= mtmp->my && mtmp->my <= chy2))))
X /* you *could* see it (ie it can see you) */
X if (fightm(mtmp) != 3)
X /* have it fight if it choses to */
X continue;
X }
X if(dochugw(mtmp))
X /* otherwise just move the monster */
X continue;
X }
X if(mtmp->mspeed == MFAST && dochugw(mtmp))
X continue;
X }
X#ifdef NAMED_ITEMS
X if (warnlevel == 100) {
X Your("%s %s!", aobjnam(uwep, "glow"),
X Hallucination ? hcolor() : light_blue);
X warnlevel = 0;
X }
X#endif
X warnlevel -= u.ulevel;
X if(warnlevel >= SIZE(warnings))
X warnlevel = SIZE(warnings)-1;
X if(!Blind && warnlevel >= 0)
X if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
X register const char *rr;
X
X switch((int) (Warning & (LEFT_RING | RIGHT_RING))){
X case LEFT_RING:
X rr = "Your left ring glows";
X break;
X case RIGHT_RING:
X rr = "Your right ring glows";
X break;
X case LEFT_RING | RIGHT_RING:
X rr = "Both your rings glow";
X break;
X default:
X { char buf[33];
X Sprintf(buf, "Your %s glow", makeplural(body_part(FINGERTIP)));
X rr = buf;
X }
X break;
X }
X pline("%s %s!", rr, Hallucination ? hcolor() : warnings[warnlevel]);
X lastwarntime = moves;
X lastwarnlev = warnlevel;
X }
X
X dmonsfree(); /* remove all dead monsters */
X}
X
X#endif /* OVL1 */
X#ifdef OVLB
X
Xvoid
Xmeatgold(mtmp)
X register struct monst *mtmp;
X{
X register struct gold *gold;
X register struct obj *otmp;
X
X /* Eats gold if it is there */
X if(gold = g_at(mtmp->mx, mtmp->my)){
X if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X pline("%s eats some gold!", Monnam(mtmp));
X mtmp->meating = (int)((gold->amount + 500L)/1000L);
X freegold(gold);
X /* Left behind a pile? */
X if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X newsym(mtmp->mx, mtmp->my);
X }
X /* Eats topmost metal object if it is there */
X for (otmp = level.objects[mtmp->mx][mtmp->my];
X otmp; otmp = otmp->nexthere)
X if (objects[otmp->otyp].oc_material > WOOD &&
X objects[otmp->otyp].oc_material < MINERAL) {
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s eats %s!", Monnam(mtmp),
X distant_name(otmp,doname));
X else if (flags.soundok && flags.verbose)
X You("hear a crunching sound.");
X mtmp->meating = otmp->owt/2 - 1;
X /* Heal up to the object's weight in hp */
X if (mtmp->mhp < mtmp->mhpmax) {
X mtmp->mhp += objects[otmp->otyp].oc_weight;
X if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
X }
X if(otmp == uball) {
X unpunish();
X freeobj(otmp);
X } else if(otmp == uchain)
X unpunish(); /* frees uchain */
X else
X freeobj(otmp);
X /* Left behind a pile? */
X if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X newsym(mtmp->mx, mtmp->my);
X break;
X }
X}
X
Xvoid
Xmeatobj(mtmp) /* for gelatinous cubes */
X register struct monst *mtmp;
X{
X register struct obj *otmp, *otmp2;
X
X /* Eats organic, glass, or wood objects if there */
X /* Engulfs others, except huge rocks and metal attached to player */
X for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
X otmp2 = otmp->nexthere;
X if(objects[otmp->otyp].oc_material <= WOOD) {
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s eats %s!", Monnam(mtmp),
X distant_name(otmp, doname));
X else if (flags.soundok && flags.verbose)
X You("hear a slurping sound.");
X /* Heal up to the object's weight in hp */
X if (mtmp->mhp < mtmp->mhpmax) {
X mtmp->mhp += objects[otmp->otyp].oc_weight;
X if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
X }
X delobj(otmp); /* munch */
X } else if (otmp->olet != ROCK_SYM &&
X otmp != uball && otmp != uchain) {
X if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X pline("%s engulfs %s.", Monnam(mtmp),
X distant_name(otmp,doname));
X freeobj(otmp);
X mpickobj(mtmp, otmp); /* slurp */
X }
X /* Engulf & devour is instant, so don't set meating */
X newsym(mtmp->mx, mtmp->my);
X }
X}
X
Xvoid
Xmpickgold(mtmp)
X register struct monst *mtmp;
X{
X register struct gold *gold;
X
X if(gold = g_at(mtmp->mx, mtmp->my)){
X mtmp->mgold += gold->amount;
X if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X pline("%s picks up some gold.", Monnam(mtmp));
X freegold(gold);
X if(levl[mtmp->mx][mtmp->my].scrsym == GOLD_SYM)
X newsym(mtmp->mx, mtmp->my);
X }
X}
X
X/* Now includes giants which pick up enormous rocks. KAA */
Xvoid
Xmpickgems(mtmp)
X register struct monst *mtmp;
X{
X register struct obj *otmp;
X
X for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp=otmp->nexthere)
X if(throws_rocks(mtmp->data) ? otmp->otyp == BOULDER :
X (otmp->olet == GEM_SYM && otmp->otyp < LAST_GEM+6))
X if(mtmp->data->mlet != S_UNICORN
X || objects[otmp->otyp].g_val != 0){
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s picks up %s.", Monnam(mtmp),
X distant_name(otmp, doname));
X freeobj(otmp);
X mpickobj(mtmp, otmp);
X newsym(mtmp->mx, mtmp->my);
X return; /* pick only one object */
X }
X}
X
X#endif /* OVLB */
X#ifdef OVL0
X
Xint
Xcurr_mon_load(mtmp)
Xregister struct monst *mtmp;
X{
X register int curload = 0;
X register struct obj *obj;
X
X for(obj = mtmp->minvent; obj; obj = obj->nobj) {
X if(obj->otyp != BOULDER || !throws_rocks(mtmp->data))
X curload += weight(obj);
X }
X
X return curload;
X}
X
Xint
Xmax_mon_load(mtmp)
Xregister struct monst *mtmp;
X{
X register int maxload;
X
X /* Base monster carrying capacity is equal to human maximum
X * carrying capacity, or half human maximum if not strong.
X * (for a polymorphed player, the value used would be the
X * non-polymorphed carrying capacity instead of max/half max).
X * This is then modified by the ratio between the monster weights
X * and human weights (weight of a human=45). Limits for corpseless
X * monsters are arbitrary.
X */
X if (!mtmp->data->cwt)
X maxload = MAX_CARR_CAP * (mtmp->data->mlevel * 6) / 45;
X else if (!strongmonst(mtmp->data)
X || (strongmonst(mtmp->data) && (mtmp->data->cwt > 45)))
X maxload = MAX_CARR_CAP * mtmp->data->cwt / 45;
X else maxload = MAX_CARR_CAP; /* strong monsters w/ cwt <= 45 */
X
X if (!strongmonst(mtmp->data)) maxload /= 2;
X
X return maxload;
X}
X
X/* for restricting monsters' object-pickup */
Xboolean
Xcan_carry(mtmp,otmp)
Xstruct monst *mtmp;
Xstruct obj *otmp;
X{
X register int newload = weight(otmp);
X
X if (otmp->otyp == CORPSE && otmp->corpsenm == PM_COCKATRICE
X && !resists_ston(mtmp->data))
X return(FALSE);
X if (mtmp->isshk) return(TRUE); /* no limit */
X if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE);
X /* otherwise players might find themselves obligated to violate
X * their alignment if the monster takes something they need
X */
X
X /* special--boulder throwers carry unlimited amounts of boulders */
X if (throws_rocks(mtmp->data) && otmp->otyp == BOULDER)
X return(TRUE);
X
X /* nymphs deal in stolen merchandise, but not boulders or statues */
X if (mtmp->data->mlet == S_NYMPH)
X return !(otmp->olet == ROCK_SYM);
X
X if(curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return(FALSE);
X
X return(TRUE);
X}
X
X#endif /* OVL0 */
X#ifdef OVL2
X
Xvoid
Xmpickstuff(mtmp, str)
X register struct monst *mtmp;
X register const char *str;
X{
X register struct obj *otmp;
X
X/* prevent shopkeepers from leaving the door of their shop */
X if(mtmp->isshk && inhishop(mtmp)) return;
X
X for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp=otmp->nexthere)
X if(index(str, otmp->olet)) {
X if(!can_carry(mtmp,otmp)) return;
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s picks up %s.", Monnam(mtmp), doname(otmp));
X freeobj(otmp);
X mpickobj(mtmp, otmp);
X if(index(str, (char) levl[mtmp->mx][mtmp->my].scrsym))
X newsym(mtmp->mx, mtmp->my);
X return; /* pick only one object */
X }
X}
X
X#endif /* OVL2 */
X#ifdef OVL0
X
X/* return number of acceptable neighbour positions */
Xint
Xmfndpos(mon, poss, info, flag)
X register struct monst *mon;
X coord *poss; /* coord poss[9] */
X long *info; /* long info[9] */
X long flag;
X{
X register int x,y,nx,ny,cnt = 0;
X register uchar ntyp;
X uchar nowtyp;
X boolean wantpool,poolok,nodiag;
X
X x = mon->mx;
X y = mon->my;
X nowtyp = levl[x][y].typ;
X
X nodiag = (mon->data == &mons[PM_GRID_BUG]);
X wantpool = mon->data->mlet == S_EEL;
X poolok = is_flyer(mon->data) || (is_swimmer(mon->data) && !wantpool);
Xnexttry: /* eels prefer the water, but if there is no water nearby,
X they will crawl over land */
X if(mon->mconf) {
X flag |= ALLOW_ALL;
X flag &= ~NOTONL;
X }
X if(!mon->mcansee)
X flag |= ALLOW_SSM;
X for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
X if((nx == x && ny == y) || !isok(nx,ny)) continue;
X if(nx != x && ny != y && nodiag) continue;
X if(IS_ROCK(ntyp = levl[nx][ny].typ) && !(flag & ALLOW_WALL) &&
X !((flag & ALLOW_DIG) && may_dig(nx,ny))) continue;
X if(IS_DOOR(ntyp) && !amorphous(mon->data) &&
X ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
X (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))
X ) && !(flag & (ALLOW_WALL|ALLOW_DIG|BUSTDOOR))) continue;
X if(nx != x && ny != y &&
X#ifdef REINCARNATION
X ((IS_DOOR(nowtyp) &&
X ((levl[x][y].doormask & ~D_BROKEN) || dlevel == rogue_level)) ||
X (IS_DOOR(ntyp) &&
X ((levl[nx][ny].doormask & ~D_BROKEN) || dlevel == rogue_level))
X#else
X ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) ||
X (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN))
X#endif
X ))
X continue;
X if(is_pool(nx,ny) == wantpool || poolok) {
X /* Displacement also displaces the Elbereth/scare monster,
X * as long as you are visible.
X */
X int dispx = (Displaced && (!Invis || perceives(mon->data)) &&
X (mon->mux==nx)) ? u.ux : nx;
X int dispy = (Displaced && (!Invis || perceives(mon->data)) &&
X (mon->muy==ny)) ? u.uy : ny;
X
X info[cnt] = 0;
X if(sobj_at(SCR_SCARE_MONSTER, dispx, dispy)
X#ifdef ELBERETH
X || sengr_at("Elbereth", dispx, dispy)
X#endif
X ) {
X if(!(flag & ALLOW_SSM)) continue;
X info[cnt] |= ALLOW_SSM;
X }
X if((nx == u.ux && ny == u.uy) ||
X (nx == mon->mux && ny == mon->muy)) {
X if(!(flag & ALLOW_U)) continue;
X info[cnt] |= ALLOW_U;
X } else {
X if(MON_AT(nx, ny)) {
X if(!(flag & ALLOW_M)) continue;
X info[cnt] |= ALLOW_M;
X if((m_at(nx,ny))->mtame) {
X if(!(flag & ALLOW_TM)) continue;
X info[cnt] |= ALLOW_TM;
X }
X }
X#if defined(ALTARS) && defined(THEOLOGY)
X /* Note: ALLOW_SANCT only prevents movement, not */
X /* attack, into a temple. */
X if(!in_temple(x, y) && in_temple(nx, ny) &&
X u_in_sanctuary(in_temple(nx, ny))) {
X if(!(flag & ALLOW_SANCT)) continue;
X info[cnt] |= ALLOW_SANCT;
X }
X#endif
X }
X if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
X if(flag & NOGARLIC) continue;
X info[cnt] |= NOGARLIC;
X }
X if(sobj_at(BOULDER, nx, ny)) {
X if(!(flag & ALLOW_ROCK)) continue;
X info[cnt] |= ALLOW_ROCK;
X }
X if((!Invis || perceives(mon->data)) && online(nx,ny)){
X if(flag & NOTONL) continue;
X info[cnt] |= NOTONL;
X }
X /* we cannot avoid traps of an unknown kind */
X { register struct trap *ttmp = t_at(nx, ny);
X register long tt;
X if(ttmp) {
X/* tt = 1L << ttmp->ttyp;*/
X/* why don't we just have code look like what it's supposed to do? then it
X/* might start working for every case. try this instead: -sac */
X tt = (ttmp->ttyp < TRAPNUM && ttmp->ttyp);
X /* below if added by GAN 02/06/87 to avoid
X * traps out of range
X */
X if(!(tt & ALLOW_TRAPS)) {
Ximpossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp);
X continue;
X }
X if(mon->mtrapseen & tt) {
X
X if(!(flag & tt)) continue;
X info[cnt] |= tt;
X }
X }
X }
X poss[cnt].x = nx;
X poss[cnt].y = ny;
X cnt++;
X }
X }
X if(!cnt && wantpool && !is_pool(x,y)) {
X wantpool = FALSE;
X goto nexttry;
X }
X return(cnt);
X}
X
X#endif /* OVL0 */
X#ifdef OVL1
X
Xint
Xdist(x, y)
Xregister int x,y;
X{
X register int dx = x - u.ux, dy = y - u.uy;
X return dx*dx + dy*dy;
X}
X
Xboolean
Xmonnear(mon, x, y)
Xregister struct monst *mon;
Xregister int x,y;
X/* Is the square close enough for the monster to move or attack into? */
X{
X register int distance = dist2(mon->mx, mon->my, x, y);
X if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0;
X return (distance < 3);
X}
X
X#endif /* OVL1 */
X#ifdef OVLB
X
Xstatic const char *poiseff[] = {
X
X " feel very weak", "r brain is on fire",
X " can't think straight", "r muscles won't obey you",
X " feel very sick", " break out in hives"
X};
X
Xvoid
Xpoisontell(typ)
X
X int typ;
X{
X pline("You%s.", poiseff[typ]);
X}
X
Xvoid
Xpoisoned(string, typ, pname, fatal)
Xregister const char *string, *pname;
Xregister int typ, fatal;
X{
X register int i, plural;
X boolean thrown_weapon = !strncmp(string, "poison", 6);
X /* admittedly a kludge... */
X
X if(strcmp(string, "blast") && !thrown_weapon) {
X /* 'blast' has already given a 'poison gas' message */
X /* so have "poison arrow", "poison dart", etc... */
X plural = (string[strlen(string) - 1] == 's')? 1 : 0;
X if(Blind)
X pline("%s poisoned.", plural ? "They were" : "It was");
X#ifdef INFERNO
X /* avoid "The" Orcus's sting was poisoned... */
X else if(isupper(*string))
X pline("%s %s poisoned!", string, plural ? "were" : "was");
X#endif
X else
X pline("The %s %s poisoned!", string, plural ? "were" : "was");
X }
X
X if(Poison_resistance) {
X if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy);
X pline("The poison doesn't seem to affect you.");
X return;
X }
X i = rn2(fatal + 20*thrown_weapon);
X if(i == 0 && typ != A_CHA) {
X u.uhp = -1;
X pline("The poison was deadly...");
X } else if(i <= 5) {
X You("%s!", poiseff[typ]);
X adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), TRUE);
X } else {
X losehp(thrown_weapon ? rnd(6) : rn1(10,6), pname, KILLED_BY_AN);
X }
X if(u.uhp < 1) {
X killer_format = KILLED_BY_AN;
X killer = pname;
X done(POISONING);
X }
X}
X
Xstatic void
Xm_detach(mtmp)
Xregister struct monst *mtmp;
X{
X#ifdef WALKIES
X if(mtmp->mleashed) m_unleash(mtmp);
X#endif
X relobj(mtmp,1);
X unpmon(mtmp);
X relmon(mtmp);
X unstuck(mtmp);
X}
X
Xvoid
Xmondead(mtmp)
Xregister struct monst *mtmp;
X{
X m_detach(mtmp);
X#ifdef KOPS
X if(mtmp->data->mlet == S_KOP && allow_kops) {
X /* Dead Kops may come back. */
X switch(rnd(5)) {
X case 1: /* returns near the stairs */
X (void) makemon(mtmp->data,xdnstair,ydnstair);
X break;
X case 2: /* randomly */
X (void) makemon(mtmp->data,0,0);
X break;
X default:
X break;
X }
X }
X#endif
X if(mtmp->isshk) shkdead(mtmp);
X if(mtmp->isgd) {
X if(!grddead(mtmp)) return;
X }
X#ifdef WORM
X if(mtmp->wormno) wormdead(mtmp);
X#endif
X#ifdef HARD
X if(mtmp->iswiz) wizdead(mtmp);
X#endif
X#ifdef MEDUSA
X if(mtmp->data == &mons[PM_MEDUSA]) u.ukilled_medusa = TRUE;
X#endif
X monfree(mtmp);
X}
X
X/* called when monster is moved to larger structure */
Xvoid
Xreplmon(mtmp, mtmp2)
Xregister struct monst *mtmp, *mtmp2;
X{
X relmon(mtmp);
X monfree(mtmp);
X place_monster(mtmp2, mtmp2->mx, mtmp2->my);
X mtmp2->nmon = fmon;
X fmon = mtmp2;
X if(u.ustuck == mtmp) u.ustuck = mtmp2;
X if(mtmp2->isshk) replshk(mtmp,mtmp2);
X#ifdef WORM
X if(mtmp2->wormno) {
X /* Each square the worm is on has a pointer; fix them all */
X register struct wseg *wtmp;
X
X for(wtmp=wsegs[mtmp2->wormno]; wtmp; wtmp=wtmp->nseg)
X place_worm_seg(mtmp2, wtmp->wx, wtmp->wy);
X }
X#endif
X}
X
Xvoid
Xrelmon(mon)
Xregister struct monst *mon;
X{
X register struct monst *mtmp;
X
X if (fmon == 0) panic ("relmon: no fmon available.");
X
X remove_monster(mon->mx, mon->my);
X
X if(mon == fmon) fmon = fmon->nmon;
X else {
X for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ;
X if(mtmp) mtmp->nmon = mon->nmon;
X else panic("relmon: mon not in list.");
X }
X}
X
X/* we do not free monsters immediately, in order to have their name
X available shortly after their demise */
Xvoid
Xmonfree(mtmp) register struct monst *mtmp; {
X mtmp->nmon = fdmon;
X fdmon = mtmp;
X remove_monster(mtmp->mx, mtmp->my);
X}
X
Xvoid
Xunstuck(mtmp)
Xregister struct monst *mtmp;
X{
X if(u.ustuck == mtmp) {
X if(u.uswallow){
X u.ux = mtmp->mx;
X u.uy = mtmp->my;
X u.uswallow = 0;
X u.uswldtim = 0;
X setsee();
X docrt();
X }
X u.ustuck = 0;
X }
X}
X
Xvoid
Xkilled(mtmp)
Xregister struct monst *mtmp;
X{
X xkilled(mtmp, 1);
X}
X
Xvoid
Xxkilled(mtmp, dest)
X register struct monst *mtmp;
X/*
X * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse
X * either; dest=3, message but no corpse
X */
X int dest;
X{
X register int tmp, nk, x, y;
X register struct permonst *mdat = mtmp->data;
X register struct obj *otmp;
X boolean chance;
X
X if (dest & 1) {
X if(!cansee(mtmp->mx,mtmp->my)) You("destroy it!");
X else {
X You("destroy %s!",
X mtmp->mtame ? a2_monnam(mtmp, "poor") : mon_nam(mtmp));
X }
X }
X
X /* restore chameleon, lycanthropes to true form at death */
X /* cannot do this in make_corpse() since genociding monsters after
X * MAXMONNO were killed does the wrong type
X */
X if(mtmp->cham) mtmp->data = mdat = &mons[PM_CHAMELEON];
X if(mdat == &mons[PM_JACKALWERE])
X mtmp->data = mdat = &mons[PM_WEREJACKAL];
X if(mdat == &mons[PM_WOLFWERE])
X mtmp->data = mdat = &mons[PM_WEREWOLF];
X if(mdat == &mons[PM_RATWERE])
X mtmp->data = mdat = &mons[PM_WERERAT];
X
X /* if we have killed MAXMONNO monsters of a given type, and it
X * can be done, genocide that monster.
X */
X tmp = monsndx(mdat);
X u.nr_killed[tmp]++;
X nk = u.nr_killed[tmp];
X#ifdef TOLKIEN
X if(nk > (tmp==PM_NAZGUL ? 9 : MAXMONNO) &&
X !(mons[tmp].geno & (G_NOGEN | G_GENOD))) {
X#else
X if(nk > MAXMONNO && !(mons[tmp].geno & (G_NOGEN | G_GENOD))) {
X#endif
X#ifdef DEBUG
X pline("Automatically genocided %s.", makeplural(mons[tmp].mname));
X#endif
X if (tmp != PM_WIZARD_OF_YENDOR)
X mons[tmp].geno |= G_GENOD;
X }
X#ifdef MAIL
X /* If you kill the mail daemon, no more mail delivery. -3. */
X else if(tmp==PM_MAIL_DAEMON) mons[tmp].geno |= G_GENOD;
X#endif
X
X /* punish bad behaviour */
X if(is_human(mdat) && !always_hostile(mdat) &&
X (monsndx(mdat) < PM_ARCHEOLOGIST || monsndx(mdat) > PM_WIZARD) &&
X u.ualigntyp != U_CHAOTIC) {
X HTelepat &= ~INTRINSIC;
X change_luck(-2);
X }
X if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1);
X if ((mdat==&mons[PM_BLACK_UNICORN] && u.ualigntyp == U_CHAOTIC) ||
X (mdat==&mons[PM_GRAY_UNICORN] && u.ualigntyp == U_NEUTRAL) ||
X (mdat==&mons[PM_WHITE_UNICORN] && u.ualigntyp == U_LAWFUL))
X change_luck(-5);
X
X /* give experience points */
X tmp = experience(mtmp, nk);
X more_experienced(tmp, 0);
X newexplevel(); /* will decide if you go up */
X
X /* adjust alignment points */
X if(mtmp->mtame)
X adjalign(-15); /* bad!! */
X#if defined(ALTARS) && defined(THEOLOGY)
X else if (mtmp->ispriest && !p_coaligned(mtmp))
X adjalign(2);
X#endif
X else if (mtmp->mpeaceful)
X adjalign(-5);
X /* malign was already adjusted for ualigntyp and randomization */
X adjalign(mtmp->malign);
X
X /* dispose of monster and make cadaver */
X if(stoned) {
X monstone(mtmp);
X return;
X }
X
X x = mtmp->mx; y = mtmp->my;
X
X mondead(mtmp);
X
X if((dest & 2)
X#ifdef REINCARNATION
X || dlevel == rogue_level
X#endif
X ) return;
X
X#ifdef MAIL
X if(mdat == &mons[PM_MAIL_DAEMON]) {
X (void) mksobj_at(SCR_MAIL, x, y);
X stackobj(fobj);
X newsym(x,y);
X }
X#endif
X if(!accessible(x, y)) {
X /* might be mimic in wall or dead eel*/
X newsym(x,y);
X } else if(x != u.ux || y != u.uy) {
X /* might be here after swallowed */
X if (!rn2(6) && !(mdat->geno & G_NOCORPSE)
X#ifdef KOPS
X && mdat->mlet != S_KOP
X#endif
X ) {
X int typ;
X
X otmp = mkobj_at(RANDOM_SYM, x, y, TRUE);
X /* Don't create large objects from small monsters */
X typ = otmp->otyp;
X if (mdat->msize < MZ_HUMAN && typ != FOOD_RATION
X#ifdef WALKIES
X && typ != LEASH
X#endif
X && typ != FIGURINE
X && (otmp->owt > 3 ||
X (typ >= SPEAR && typ <= LANCE) ||
X (typ >= SCIMITAR && typ <= KATANA) ||
X (typ == MORNING_STAR || typ == QUARTERSTAFF) ||
X (typ >= BARDICHE && typ <= VOULGE) ||
X (typ>=PLATE_MAIL && typ<=DRAGON_SCALE_MAIL) ||
X (typ == LARGE_SHIELD))) {
X delobj(otmp);
X } else newsym(x,y);
X }
X /* Whether or not it always makes a corpse is, in theory,
X * different from whether or not the corpse is "special";
X * if we want both, we have to specify it explicitly.
X */
X if (bigmonst(mdat) || mdat == &mons[PM_LIZARD]
X#ifdef GOLEMS
X || is_golem(mdat)
X#endif
X ) chance = 1;
X else chance = !rn2((int)
X (2 + ((mdat->geno & G_FREQ)<2) + verysmall(mdat)));
X if (chance)
X (void) make_corpse(mtmp);
X }
X}
X
Xvoid
Xrescham() { /* force all chameleons to become normal */
X
X register struct monst *mtmp;
X
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X if(mtmp->cham) {
X mtmp->cham = 0;
X (void) newcham(mtmp, &mons[PM_CHAMELEON]);
X }
X if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
X (void) new_were(mtmp);
X if(mtmp->mimic && cansee(mtmp->mx, mtmp->my)) {
X seemimic(mtmp);
X /* we pretend that the mimic doesn't */
X /* know that it has been unmasked. */
X mtmp->msleep = 1;
X }
X }
X}
X
X/* Let the chameleons change again -dgk */
Xvoid
Xrestartcham() {
X
X register struct monst *mtmp;
X
X for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X if (mtmp->data == &mons[PM_CHAMELEON])
X mtmp->cham = 1;
X if(mtmp->data->mlet == S_MIMIC && mtmp->msleep &&
X cansee(mtmp->mx, mtmp->my)) {
X set_mimic_sym(mtmp);
X unpmon(mtmp);
X pmon(mtmp);
X }
X }
X}
X
Xint
Xnewcham(mtmp, mdat) /* make a chameleon look like a new monster */
X /* returns 1 if the monster actually changed */
X register struct monst *mtmp;
X register struct permonst *mdat;
X{
X register int mhp, hpn, hpd;
X int tryct;
X struct permonst *olddata = mtmp->data;
X
X /* mdat = 0 -> caller wants a random monster shape */
X tryct = 0;
X if(mdat == 0) {
X while (++tryct < 100) {
X static int NEARDATA num;
X mdat = &mons[num=rn2(NUMMONS)];
X if ((!is_human(mdat) || num == PM_NURSE)
X && !type_is_pname(mdat)
X && !is_were(mdat)
X#ifdef MEDUSA
X && num != PM_MEDUSA
X#endif
X#ifdef MAIL
X && num != PM_MAIL_DAEMON
X#endif
X )
X break;
X }
X if (tryct >= 100) return(0); /* Should never happen */
X }
X if(mdat == mtmp->data) return(0); /* still the same monster */
X
X#ifdef WORM
X if(mtmp->wormno) wormdead(mtmp); /* throw tail away */
X#endif
X hpn = mtmp->mhp;
X hpd = (mtmp->m_lev < 50) ? (mtmp->m_lev)*8 : mdat->mlevel;
X if(!hpd) hpd = 4;
X
X mtmp->m_lev = adj_lev(mdat); /* new monster level */
X
X mhp = (mtmp->m_lev < 50) ? (mtmp->m_lev)*8 : mdat->mlevel;
X if(!mhp) mhp = 4;
X
X /* new hp: same fraction of max as before */
X#ifndef LINT
X mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd);
X#endif
X if(mtmp->mhp < 0) mtmp->mhp = hpn; /* overflow */
X/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
X 0HD creature will require this statement */
X if (!mtmp->mhp) mtmp->mhp = 1;
X
X/* and the same for maximum hit points */
X hpn = mtmp->mhpmax;
X#ifndef LINT
X mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd);
X#endif
X if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn; /* overflow */
X if (!mtmp->mhpmax) mtmp->mhpmax = 1;
X
X mtmp->data = mdat;
X mtmp->minvis = !!(mdat->mlet == S_STALKER);
X mtmp->mhide = !!hides_under(mdat);
X if (!mtmp->mhide) mtmp->mundetected = 0;
X if (u.ustuck == mtmp) {
X if(u.uswallow) {
X if(!attacktype(mdat,AT_ENGL)) {
X /* Does mdat care? */
X if (!noncorporeal(mdat) && !amorphous(mdat) &&
X !is_whirly(mdat) &&
X (mdat != &mons[PM_YELLOW_LIGHT])) {
X You("break out of %s%s!", mon_nam(mtmp),
X (is_animal(mdat)?
X "'s stomach" : ""));
X mtmp->mhp = 1; /* almost dead */
X }
X expels(mtmp, olddata, FALSE);
X }
X } else {
X if(!sticks(mdat)
X#ifdef POLYSELF
X && !sticks(uasmon)
X#endif
X )
X unstuck(mtmp);
X }
X }
X
X#ifdef WORM
X if(mdat == &mons[PM_LONG_WORM] && getwn(mtmp)) initworm(mtmp);
X#endif
X unpmon(mtmp); /* necessary for 'I' and to force pmon */
X pmon(mtmp);
X return(1);
X}
X
Xvoid
Xmnexto(mtmp) /* Make monster mtmp next to you (if possible) */
X struct monst *mtmp;
X{
X coord mm;
X if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return;
X remove_monster(mtmp->mx, mtmp->my);
X place_monster(mtmp, mm.x, mm.y);
X pmon(mtmp);
X set_apparxy(mtmp);
X}
X
Xvoid
Xmnearto(mtmp,x,y,gz) /* Make monster near (or at) location if possible */
X register struct monst *mtmp;
X xchar x, y;
X boolean gz;
X{
X coord mm;
X if(!gz || !goodpos(x,y,mtmp->data)) {
X if(!enexto(&mm, x, y, mtmp->data)) return;
X x = mm.x; y = mm.y;
X }
X if(x == mtmp->mx && y == mtmp->my) /* that was easy */
X return;
X remove_monster(mtmp->mx, mtmp->my);
X place_monster(mtmp, x, y);
X pmon(mtmp);
X set_apparxy(mtmp);
X}
X
X#endif /* OVLB */
X#ifdef OVL2
X
Xvoid
Xsetmangry(mtmp)
X register struct monst *mtmp;
X{
X if(!mtmp->mpeaceful) return;
X if(mtmp->mtame) return;
X mtmp->mpeaceful = 0;
X#if defined(ALTARS) && defined(THEOLOGY)
X if(mtmp->ispriest) {
X if(p_coaligned(mtmp)) adjalign(-5); /* very bad */
X else adjalign(2);
X } else
X#endif
X adjalign(-1); /* attacking peaceful monsters is bad */
X if(humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd)
X pline("%s gets angry!", Monnam(mtmp));
X#ifdef SOUNDS
X else if (flags.verbose && flags.soundok) growl(mtmp);
X#endif
X}
X
Xint
Xdisturb(mtmp) /* awaken monsters while in the same room.
X * return a 1 if they have been woken.
X */
X register struct monst *mtmp;
X{
X /* wake up, or get out of here. */
X /* ettins are hard to surprise */
X /* Nymphs and Leprechauns do not easily wake up */
X if(cansee(mtmp->mx,mtmp->my) &&
X (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) &&
X (!(mtmp->data->mlet == S_NYMPH
X || mtmp->data == &mons[PM_JABBERWOCK]
X || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) &&
X (Aggravate_monster ||
X (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_HUMAN) ||
X (!rn2(7) && !mtmp->mimic))) {
X mtmp->msleep = 0;
X return(1);
X }
X if(Hallucination) pmon(mtmp);
X return(0);
X}
X
X#ifdef HARD
XSTATIC_OVL boolean
Xrestrap(mtmp)
X/* unwatched hiders may hide again,
X * if so, a 1 is returned.
X */
Xregister struct monst *mtmp;
X{
X if(mtmp->cham || mtmp->mcan || mtmp->mimic ||
X cansee(mtmp->mx, mtmp->my) || rn2(3))
X return(FALSE);
X
X if(mtmp->data->mlet == S_MIMIC) {
X set_mimic_sym(mtmp);
X return(TRUE);
X } else
X if(levl[mtmp->mx][mtmp->my].typ == ROOM) {
X (void) maketrap(mtmp->mx, mtmp->my, MONST_TRAP);
X /* override type selection */
X ftrap->pm = monsndx(mtmp->data);
X mondead(mtmp);
X return(TRUE);
X }
X
X return(FALSE);
X}
X#endif
X
X#endif /* OVL2 */
X#ifdef OVLB
X
X/* drop (perhaps) a cadaver and remove monster */
Xvoid
Xmondied(mdef)
Xregister struct monst *mdef;
X{
X mondead(mdef);
X if(rn2(3)
X#ifdef REINCARNATION
X && dlevel != rogue_level
X#endif
X )
X (void) make_corpse(mdef);
X}
X
X/* monster disappears, not dies */
Xvoid
Xmongone(mdef)
Xregister struct monst *mdef;
X{
X register struct obj *otmp, *otmp2;
X
X /* release monster's inventory */
X for (otmp = mdef->minvent; otmp; otmp = otmp2) {
X otmp2 = otmp->nobj;
X obfree(otmp, (struct obj *)0);
X }
X mdef->minvent = 0;
X mdef->mgold = 0;
X m_detach(mdef);
X monfree(mdef);
X}
X
X/* drop a statue or rock and remove monster */
Xvoid
Xmonstone(mdef)
Xregister struct monst *mdef;
X{
X struct obj *otmp;
X
X if((int)mdef->data->msize > MZ_TINY ||
X !rn2(2 + ((mdef->data->geno & G_FREQ) > 2))) {
X otmp = mk_named_object(STATUE, mdef->data, mdef->mx, mdef->my,
X NAME(mdef), (int)mdef->mnamelth);
X otmp->spe = 0; /* no book inside */
X } else
X (void) mksobj_at(ROCK, mdef->mx, mdef->my);
X
X stackobj(fobj);
X
X if(cansee(mdef->mx, mdef->my)){
X unpmon(mdef);
X atl(mdef->mx,mdef->my,Hallucination ? rndobjsym() : fobj->olet);
X }
X mondead(mdef);
X}
X
X#ifdef GOLEMS
Xvoid
Xgolemeffects(mon, damtype, dam)
Xregister struct monst *mon;
Xint damtype, dam;
X{
X int heal=0, slow=0;
X
X if (mon->data != &mons[PM_FLESH_GOLEM]
X && mon->data != &mons[PM_IRON_GOLEM])
X return;
X
X if (mon->data == &mons[PM_FLESH_GOLEM]) {
X if (damtype == AD_ELEC) heal = dam / 6;
X else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1;
X } else {
X if (damtype == AD_ELEC) slow = 1;
X else if (damtype == AD_FIRE) heal = dam;
X }
X if (slow) {
X if (mon->mspeed != MSLOW) {
X if (mon->mspeed == MFAST) mon->mspeed = 0;
X else mon->mspeed = MSLOW;
X if (cansee(mon->mx, mon->my))
X pline("%s seems to be moving slower.",
X Monnam(mon));
X }
X }
X if (heal) {
X if (mon->mhp < mon->mhpmax) {
X mon->mhp += dam;
X if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
X if (cansee(mon->mx, mon->my))
X pline("%s seems healthier.", Monnam(mon));
X }
X }
X}
X#endif /* GOLEMS */
X
X#endif /* OVLB */
END_OF_FILE
if test 36529 -ne `wc -c <'src/mon.c'`; then
echo shar: \"'src/mon.c'\" unpacked with wrong size!
fi
# end of 'src/mon.c'
fi
echo shar: End of archive 17 \(of 56\).
cp /dev/null ark17isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 56 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0