billr@saab.CNA.TEK.COM (Bill Randle) (07/12/90)
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