freebsd-dev/games/hack/hack.mon.c
Jordan K. Hubbard 554eb505f8 Bring in the 4.4 Lite games directory, modulo man page changes and segregation
of the x11 based games.  I'm not going to tag the originals with bsd_44_lite
and do this in two stages since it's just not worth it for this collection,
and I've got directory renames to deal with that way.  Bleah.
Submitted by:	jkh
1994-09-04 04:03:31 +00:00

854 lines
20 KiB
C

/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.mon.c - version 1.0.3 */
#include "hack.h"
#include "hack.mfndpos.h"
#ifndef NULL
#define NULL (char *) 0
#endif
extern struct monst *makemon();
extern struct obj *mkobj_at();
int warnlevel; /* used by movemon and dochugw */
long lastwarntime;
int lastwarnlev;
char *warnings[] = {
"white", "pink", "red", "ruby", "purple", "black"
};
movemon()
{
register struct monst *mtmp;
register int fr;
warnlevel = 0;
while(1) {
/* find a monster that we haven't treated yet */
/* note that mtmp or mtmp->nmon might get killed
while mtmp moves, so we cannot just walk down the
chain (even new monsters might get created!) */
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if(mtmp->mlstmv < moves) goto next_mon;
/* treated all monsters */
break;
next_mon:
mtmp->mlstmv = moves;
/* most monsters drown in pools */
{ boolean inpool, iseel;
inpool = (levl[mtmp->mx][mtmp->my].typ == POOL);
iseel = (mtmp->data->mlet == ';');
if(inpool && !iseel) {
if(cansee(mtmp->mx,mtmp->my))
pline("%s drowns.", Monnam(mtmp));
mondead(mtmp);
continue;
}
/* but eels have a difficult time outside */
if(iseel && !inpool) {
if(mtmp->mhp > 1) mtmp->mhp--;
mtmp->mflee = 1;
mtmp->mfleetim += 2;
}
}
if(mtmp->mblinded && !--mtmp->mblinded)
mtmp->mcansee = 1;
if(mtmp->mfleetim && !--mtmp->mfleetim)
mtmp->mflee = 0;
if(mtmp->mimic) continue;
if(mtmp->mspeed != MSLOW || !(moves%2)){
/* continue if the monster died fighting */
fr = -1;
if(Conflict && cansee(mtmp->mx,mtmp->my)
&& (fr = fightm(mtmp)) == 2)
continue;
if(fr<0 && dochugw(mtmp))
continue;
}
if(mtmp->mspeed == MFAST && dochugw(mtmp))
continue;
}
warnlevel -= u.ulevel;
if(warnlevel >= SIZE(warnings))
warnlevel = SIZE(warnings)-1;
if(warnlevel >= 0)
if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
register char *rr;
switch(Warning & (LEFT_RING | RIGHT_RING)){
case LEFT_RING:
rr = "Your left ring glows";
break;
case RIGHT_RING:
rr = "Your right ring glows";
break;
case LEFT_RING | RIGHT_RING:
rr = "Both your rings glow";
break;
default:
rr = "Your fingertips glow";
break;
}
pline("%s %s!", rr, warnings[warnlevel]);
lastwarntime = moves;
lastwarnlev = warnlevel;
}
dmonsfree(); /* remove all dead monsters */
}
justswld(mtmp,name)
register struct monst *mtmp;
char *name;
{
mtmp->mx = u.ux;
mtmp->my = u.uy;
u.ustuck = mtmp;
pmon(mtmp);
kludge("%s swallows you!",name);
more();
seeoff(1);
u.uswallow = 1;
u.uswldtim = 0;
swallowed();
}
youswld(mtmp,dam,die,name)
register struct monst *mtmp;
register dam,die;
char *name;
{
if(mtmp != u.ustuck) return;
kludge("%s digests you!",name);
u.uhp -= dam;
if(u.uswldtim++ >= die){ /* a3 */
pline("It totally digests you!");
u.uhp = -1;
}
if(u.uhp < 1) done_in_by(mtmp);
/* flags.botlx = 1; /* should we show status line ? */
}
dochugw(mtmp) register struct monst *mtmp; {
register x = mtmp->mx;
register y = mtmp->my;
register d = dochug(mtmp);
register dd;
if(!d) /* monster still alive */
if(Warning)
if(!mtmp->mpeaceful)
if(mtmp->data->mlevel > warnlevel)
if((dd = dist(mtmp->mx,mtmp->my)) < dist(x,y))
if(dd < 100)
if(!canseemon(mtmp))
warnlevel = mtmp->data->mlevel;
return(d);
}
/* returns 1 if monster died moving, 0 otherwise */
dochug(mtmp)
register struct monst *mtmp;
{
register struct permonst *mdat;
register tmp, nearby, scared;
if(mtmp->cham && !rn2(6))
(void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
mdat = mtmp->data;
if(mdat->mlevel < 0)
panic("bad monster %c (%d)",mdat->mlet,mdat->mlevel);
/* regenerate monsters */
if((!(moves%20) || index(MREGEN, mdat->mlet)) &&
mtmp->mhp < mtmp->mhpmax)
mtmp->mhp++;
if(mtmp->mfroz) return(0); /* frozen monsters don't do anything */
if(mtmp->msleep) {
/* wake up, or get out of here. */
/* ettins are hard to surprise */
/* Nymphs and Leprechauns do not easily wake up */
if(cansee(mtmp->mx,mtmp->my) &&
(!Stealth || (mdat->mlet == 'e' && rn2(10))) &&
(!index("NL",mdat->mlet) || !rn2(50)) &&
(Aggravate_monster || index("d1", mdat->mlet)
|| (!rn2(7) && !mtmp->mimic)))
mtmp->msleep = 0;
else return(0);
}
/* not frozen or sleeping: wipe out texts written in the dust */
wipe_engr_at(mtmp->mx, mtmp->my, 1);
/* confused monsters get unconfused with small probability */
if(mtmp->mconf && !rn2(50)) mtmp->mconf = 0;
/* some monsters teleport */
if(mtmp->mflee && index("tNL", mdat->mlet) && !rn2(40)){
rloc(mtmp);
return(0);
}
if(mdat->mmove < rnd(6)) return(0);
/* fleeing monsters might regain courage */
if(mtmp->mflee && !mtmp->mfleetim
&& mtmp->mhp == mtmp->mhpmax && !rn2(25))
mtmp->mflee = 0;
nearby = (dist(mtmp->mx, mtmp->my) < 3);
scared = (nearby && (sengr_at("Elbereth", u.ux, u.uy) ||
sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)));
if(scared && !mtmp->mflee) {
mtmp->mflee = 1;
mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
}
if(!nearby ||
mtmp->mflee ||
mtmp->mconf ||
(mtmp->minvis && !rn2(3)) ||
(index("BIuy", mdat->mlet) && !rn2(4)) ||
(mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) ||
(!mtmp->mcansee && !rn2(4)) ||
mtmp->mpeaceful
) {
tmp = m_move(mtmp,0); /* 2: monster died moving */
if(tmp == 2 || (tmp && mdat->mmove <= 12))
return(tmp == 2);
}
if(!index("Ea", mdat->mlet) && nearby &&
!mtmp->mpeaceful && u.uhp > 0 && !scared) {
if(mhitu(mtmp))
return(1); /* monster died (e.g. 'y' or 'F') */
}
/* extra movement for fast monsters */
if(mdat->mmove-12 > rnd(12)) tmp = m_move(mtmp,1);
return(tmp == 2);
}
m_move(mtmp,after)
register struct monst *mtmp;
{
register struct monst *mtmp2;
register nx,ny,omx,omy,appr,nearer,cnt,i,j;
xchar gx,gy,nix,niy,chcnt;
schar chi;
boolean likegold, likegems, likeobjs;
char msym = mtmp->data->mlet;
schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */
coord poss[9];
int info[9];
if(mtmp->mfroz || mtmp->msleep)
return(0);
if(mtmp->mtrapped) {
i = mintrap(mtmp);
if(i == 2) return(2); /* he died */
if(i == 1) return(0); /* still in trap, so didnt move */
}
if(mtmp->mhide && o_at(mtmp->mx,mtmp->my) && rn2(10))
return(0); /* do not leave hiding place */
#ifndef NOWORM
if(mtmp->wormno)
goto not_special;
#endif NOWORM
/* my dog gets a special treatment */
if(mtmp->mtame) {
return( dog_move(mtmp, after) );
}
/* likewise for shopkeeper */
if(mtmp->isshk) {
mmoved = shk_move(mtmp);
if(mmoved >= 0)
goto postmov;
mmoved = 0; /* follow player outside shop */
}
/* and for the guard */
if(mtmp->isgd) {
mmoved = gd_move();
goto postmov;
}
/* teleport if that lies in our nature ('t') or when badly wounded ('1') */
if((msym == 't' && !rn2(5))
|| (msym == '1' && (mtmp->mhp < 7 || (!xdnstair && !rn2(5))
|| levl[u.ux][u.uy].typ == STAIRS))) {
if(mtmp->mhp < 7 || (msym == 't' && rn2(2)))
rloc(mtmp);
else
mnexto(mtmp);
mmoved = 1;
goto postmov;
}
/* spit fire ('D') or use a wand ('1') when appropriate */
if(index("D1", msym))
inrange(mtmp);
if(msym == 'U' && !mtmp->mcan && canseemon(mtmp) &&
mtmp->mcansee && rn2(5)) {
if(!Confusion)
pline("%s's gaze has confused you!", Monnam(mtmp));
else
pline("You are getting more and more confused.");
if(rn2(3)) mtmp->mcan = 1;
Confusion += d(3,4); /* timeout */
}
not_special:
if(!mtmp->mflee && u.uswallow && u.ustuck != mtmp) return(1);
appr = 1;
if(mtmp->mflee) appr = -1;
if(mtmp->mconf || Invis || !mtmp->mcansee ||
(index("BIy", msym) && !rn2(3)))
appr = 0;
omx = mtmp->mx;
omy = mtmp->my;
gx = u.ux;
gy = u.uy;
if(msym == 'L' && appr == 1 && mtmp->mgold > u.ugold)
appr = -1;
/* random criterion for 'smell' or track finding ability
should use mtmp->msmell or sth
*/
if(msym == '@' ||
('a' <= msym && msym <= 'z')) {
extern coord *gettrack();
register coord *cp;
schar mroom;
mroom = inroom(omx,omy);
if(mroom < 0 || mroom != inroom(u.ux,u.uy)){
cp = gettrack(omx,omy);
if(cp){
gx = cp->x;
gy = cp->y;
}
}
}
/* look for gold or jewels nearby */
likegold = (index("LOD", msym) != NULL);
likegems = (index("ODu", msym) != NULL);
likeobjs = mtmp->mhide;
#define SRCHRADIUS 25
{ xchar mind = SRCHRADIUS; /* not too far away */
register int dd;
if(likegold){
register struct gold *gold;
for(gold = fgold; gold; gold = gold->ngold)
if((dd = DIST(omx,omy,gold->gx,gold->gy)) < mind){
mind = dd;
gx = gold->gx;
gy = gold->gy;
}
}
if(likegems || likeobjs){
register struct obj *otmp;
for(otmp = fobj; otmp; otmp = otmp->nobj)
if(likeobjs || otmp->olet == GEM_SYM)
if(msym != 'u' ||
objects[otmp->otyp].g_val != 0)
if((dd = DIST(omx,omy,otmp->ox,otmp->oy)) < mind){
mind = dd;
gx = otmp->ox;
gy = otmp->oy;
}
}
if(mind < SRCHRADIUS && appr == -1) {
if(dist(omx,omy) < 10) {
gx = u.ux;
gy = u.uy;
} else
appr = 1;
}
}
nix = omx;
niy = omy;
cnt = mfndpos(mtmp,poss,info,
msym == 'u' ? NOTONL :
(msym == '@' || msym == '1') ? (ALLOW_SSM | ALLOW_TRAPS) :
index(UNDEAD, msym) ? NOGARLIC : ALLOW_TRAPS);
/* ALLOW_ROCK for some monsters ? */
chcnt = 0;
chi = -1;
for(i=0; i<cnt; i++) {
nx = poss[i].x;
ny = poss[i].y;
for(j=0; j<MTSZ && j<cnt-1; j++)
if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
if(rn2(4*(cnt-j))) goto nxti;
#ifdef STUPID
/* some stupid compilers think that this is too complicated */
{ int d1 = DIST(nx,ny,gx,gy);
int d2 = DIST(nix,niy,gx,gy);
nearer = (d1 < d2);
}
#else
nearer = (DIST(nx,ny,gx,gy) < DIST(nix,niy,gx,gy));
#endif STUPID
if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
!mmoved ||
(!appr && !rn2(++chcnt))){
nix = nx;
niy = ny;
chi = i;
mmoved = 1;
}
nxti: ;
}
if(mmoved){
if(info[chi] & ALLOW_M){
mtmp2 = m_at(nix,niy);
if(hitmm(mtmp,mtmp2) == 1 && rn2(4) &&
hitmm(mtmp2,mtmp) == 2) return(2);
return(0);
}
if(info[chi] & ALLOW_U){
(void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd)+1);
return(0);
}
mtmp->mx = nix;
mtmp->my = niy;
for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
mtmp->mtrack[0].x = omx;
mtmp->mtrack[0].y = omy;
#ifndef NOWORM
if(mtmp->wormno) worm_move(mtmp);
#endif NOWORM
} else {
if(msym == 'u' && rn2(2)){
rloc(mtmp);
return(0);
}
#ifndef NOWORM
if(mtmp->wormno) worm_nomove(mtmp);
#endif NOWORM
}
postmov:
if(mmoved == 1) {
if(mintrap(mtmp) == 2) /* he died */
return(2);
if(likegold) mpickgold(mtmp);
if(likegems) mpickgems(mtmp);
if(mtmp->mhide) mtmp->mundetected = 1;
}
pmon(mtmp);
return(mmoved);
}
mpickgold(mtmp) register struct monst *mtmp; {
register struct gold *gold;
while(gold = g_at(mtmp->mx, mtmp->my)){
mtmp->mgold += gold->amount;
freegold(gold);
if(levl[mtmp->mx][mtmp->my].scrsym == '$')
newsym(mtmp->mx, mtmp->my);
}
}
mpickgems(mtmp) register struct monst *mtmp; {
register struct obj *otmp;
for(otmp = fobj; otmp; otmp = otmp->nobj)
if(otmp->olet == GEM_SYM)
if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
if(mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0){
freeobj(otmp);
mpickobj(mtmp, otmp);
if(levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM)
newsym(mtmp->mx, mtmp->my); /* %% */
return; /* pick only one object */
}
}
/* return number of acceptable neighbour positions */
mfndpos(mon,poss,info,flag)
register struct monst *mon;
coord poss[9];
int info[9], flag;
{
register int x,y,nx,ny,cnt = 0,ntyp;
register struct monst *mtmp;
int nowtyp;
boolean pool;
x = mon->mx;
y = mon->my;
nowtyp = levl[x][y].typ;
pool = (mon->data->mlet == ';');
nexttry: /* eels prefer the water, but if there is no water nearby,
they will crawl over land */
if(mon->mconf) {
flag |= ALLOW_ALL;
flag &= ~NOTONL;
}
for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++)
if(nx != x || ny != y) if(isok(nx,ny))
if(!IS_ROCK(ntyp = levl[nx][ny].typ))
if(!(nx != x && ny != y && (nowtyp == DOOR || ntyp == DOOR)))
if((ntyp == POOL) == pool) {
info[cnt] = 0;
if(nx == u.ux && ny == u.uy){
if(!(flag & ALLOW_U)) continue;
info[cnt] = ALLOW_U;
} else if(mtmp = m_at(nx,ny)){
if(!(flag & ALLOW_M)) continue;
info[cnt] = ALLOW_M;
if(mtmp->mtame){
if(!(flag & ALLOW_TM)) continue;
info[cnt] |= ALLOW_TM;
}
}
if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
if(flag & NOGARLIC) continue;
info[cnt] |= NOGARLIC;
}
if(sobj_at(SCR_SCARE_MONSTER, nx, ny) ||
(!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) {
if(!(flag & ALLOW_SSM)) continue;
info[cnt] |= ALLOW_SSM;
}
if(sobj_at(ENORMOUS_ROCK, nx, ny)) {
if(!(flag & ALLOW_ROCK)) continue;
info[cnt] |= ALLOW_ROCK;
}
if(!Invis && online(nx,ny)){
if(flag & NOTONL) continue;
info[cnt] |= NOTONL;
}
/* we cannot avoid traps of an unknown kind */
{ register struct trap *ttmp = t_at(nx, ny);
register int tt;
if(ttmp) {
tt = 1 << ttmp->ttyp;
if(mon->mtrapseen & tt){
if(!(flag & tt)) continue;
info[cnt] |= tt;
}
}
}
poss[cnt].x = nx;
poss[cnt].y = ny;
cnt++;
}
if(!cnt && pool && nowtyp != POOL) {
pool = FALSE;
goto nexttry;
}
return(cnt);
}
dist(x,y) int x,y; {
return((x-u.ux)*(x-u.ux) + (y-u.uy)*(y-u.uy));
}
poisoned(string, pname)
register char *string, *pname;
{
register int i;
if(Blind) pline("It was poisoned.");
else pline("The %s was poisoned!",string);
if(Poison_resistance) {
pline("The poison doesn't seem to affect you.");
return;
}
i = rn2(10);
if(i == 0) {
u.uhp = -1;
pline("I am afraid the poison was deadly ...");
} else if(i <= 5) {
losestr(rn1(3,3));
} else {
losehp(rn1(10,6), pname);
}
if(u.uhp < 1) {
killer = pname;
done("died");
}
}
mondead(mtmp)
register struct monst *mtmp;
{
relobj(mtmp,1);
unpmon(mtmp);
relmon(mtmp);
unstuck(mtmp);
if(mtmp->isshk) shkdead(mtmp);
if(mtmp->isgd) gddead();
#ifndef NOWORM
if(mtmp->wormno) wormdead(mtmp);
#endif NOWORM
monfree(mtmp);
}
/* called when monster is moved to larger structure */
replmon(mtmp,mtmp2)
register struct monst *mtmp, *mtmp2;
{
relmon(mtmp);
monfree(mtmp);
mtmp2->nmon = fmon;
fmon = mtmp2;
if(u.ustuck == mtmp) u.ustuck = mtmp2;
if(mtmp2->isshk) replshk(mtmp,mtmp2);
if(mtmp2->isgd) replgd(mtmp,mtmp2);
}
relmon(mon)
register struct monst *mon;
{
register struct monst *mtmp;
if(mon == fmon) fmon = fmon->nmon;
else {
for(mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon) ;
mtmp->nmon = mon->nmon;
}
}
/* we do not free monsters immediately, in order to have their name
available shortly after their demise */
struct monst *fdmon; /* chain of dead monsters, need not to be saved */
monfree(mtmp) register struct monst *mtmp; {
mtmp->nmon = fdmon;
fdmon = mtmp;
}
dmonsfree(){
register struct monst *mtmp;
while(mtmp = fdmon){
fdmon = mtmp->nmon;
free((char *) mtmp);
}
}
unstuck(mtmp)
register struct monst *mtmp;
{
if(u.ustuck == mtmp) {
if(u.uswallow){
u.ux = mtmp->mx;
u.uy = mtmp->my;
u.uswallow = 0;
setsee();
docrt();
}
u.ustuck = 0;
}
}
killed(mtmp)
register struct monst *mtmp;
{
#ifdef lint
#define NEW_SCORING
#endif lint
register int tmp,tmp2,nk,x,y;
register struct permonst *mdat;
extern long newuexp();
if(mtmp->cham) mtmp->data = PM_CHAMELEON;
mdat = mtmp->data;
if(Blind) pline("You destroy it!");
else {
pline("You destroy %s!",
mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp));
}
if(u.umconf) {
if(!Blind) pline("Your hands stop glowing blue.");
u.umconf = 0;
}
/* count killed monsters */
#define MAXMONNO 100
nk = 1; /* in case we cannot find it in mons */
tmp = mdat - mons; /* index in mons array (if not 'd', '@', ...) */
if(tmp >= 0 && tmp < CMNUM+2) {
extern char fut_geno[];
u.nr_killed[tmp]++;
if((nk = u.nr_killed[tmp]) > MAXMONNO &&
!index(fut_geno, mdat->mlet))
charcat(fut_geno, mdat->mlet);
}
/* punish bad behaviour */
if(mdat->mlet == '@') Telepat = 0, u.uluck -= 2;
if(mtmp->mpeaceful || mtmp->mtame) u.uluck--;
if(mdat->mlet == 'u') u.uluck -= 5;
if((int)u.uluck < LUCKMIN) u.uluck = LUCKMIN;
/* give experience points */
tmp = 1 + mdat->mlevel * mdat->mlevel;
if(mdat->ac < 3) tmp += 2*(7 - mdat->ac);
if(index("AcsSDXaeRTVWU&In:P", mdat->mlet))
tmp += 2*mdat->mlevel;
if(index("DeV&P",mdat->mlet)) tmp += (7*mdat->mlevel);
if(mdat->mlevel > 6) tmp += 50;
if(mdat->mlet == ';') tmp += 1000;
#ifdef NEW_SCORING
/* ------- recent addition: make nr of points decrease
when this is not the first of this kind */
{ int ul = u.ulevel;
int ml = mdat->mlevel;
if(ul < 14) /* points are given based on present and future level */
for(tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
if(u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4<<(tmp2-1)))/nk
>= 10*pow((unsigned)(ul-1)))
if(++ul == 14) break;
tmp2 = ml - ul -1;
tmp = (tmp + ((tmp2 < 0) ? 0 : 4<<tmp2))/nk;
if(!tmp) tmp = 1;
}
/* note: ul is not necessarily the future value of u.ulevel */
/* ------- end of recent valuation change ------- */
#endif NEW_SCORING
more_experienced(tmp,0);
flags.botl = 1;
while(u.ulevel < 14 && u.uexp >= newuexp()){
pline("Welcome to experience level %u.", ++u.ulevel);
tmp = rnd(10);
if(tmp < 3) tmp = rnd(10);
u.uhpmax += tmp;
u.uhp += tmp;
flags.botl = 1;
}
/* dispose of monster and make cadaver */
x = mtmp->mx; y = mtmp->my;
mondead(mtmp);
tmp = mdat->mlet;
if(tmp == 'm') { /* he killed a minotaur, give him a wand of digging */
/* note: the dead minotaur will be on top of it! */
mksobj_at(WAN_DIGGING, x, y);
/* if(cansee(x,y)) atl(x,y,fobj->olet); */
stackobj(fobj);
} else
#ifndef NOWORM
if(tmp == 'w') {
mksobj_at(WORM_TOOTH, x, y);
stackobj(fobj);
} else
#endif NOWORM
if(!letter(tmp) || (!index("mw", tmp) && !rn2(3))) tmp = 0;
if(ACCESSIBLE(levl[x][y].typ)) /* might be mimic in wall or dead eel*/
if(x != u.ux || y != u.uy) /* might be here after swallowed */
if(index("NTVm&",mdat->mlet) || rn2(5)) {
register struct obj *obj2 = mkobj_at(tmp,x,y);
if(cansee(x,y))
atl(x,y,obj2->olet);
stackobj(obj2);
}
}
kludge(str,arg)
register char *str,*arg;
{
if(Blind) {
if(*str == '%') pline(str,"It");
else pline(str,"it");
} else pline(str,arg);
}
rescham() /* force all chameleons to become normal */
{
register struct monst *mtmp;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if(mtmp->cham) {
mtmp->cham = 0;
(void) newcham(mtmp, PM_CHAMELEON);
}
}
newcham(mtmp,mdat) /* make a chameleon look like a new monster */
/* returns 1 if the monster actually changed */
register struct monst *mtmp;
register struct permonst *mdat;
{
register mhp, hpn, hpd;
if(mdat == mtmp->data) return(0); /* still the same monster */
#ifndef NOWORM
if(mtmp->wormno) wormdead(mtmp); /* throw tail away */
#endif NOWORM
if (u.ustuck == mtmp) {
if (u.uswallow) {
u.uswallow = 0;
u.uswldtim = 0;
mnexto (mtmp);
docrt ();
prme ();
}
u.ustuck = 0;
}
hpn = mtmp->mhp;
hpd = (mtmp->data->mlevel)*8;
if(!hpd) hpd = 4;
mtmp->data = mdat;
mhp = (mdat->mlevel)*8;
/* new hp: same fraction of max as before */
mtmp->mhp = 2 + (hpn*mhp)/hpd;
hpn = mtmp->mhpmax;
mtmp->mhpmax = 2 + (hpn*mhp)/hpd;
mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0;
#ifndef NOWORM
if(mdat->mlet == 'w' && getwn(mtmp)) initworm(mtmp);
/* perhaps we should clear mtmp->mtame here? */
#endif NOWORM
unpmon(mtmp); /* necessary for 'I' and to force pmon */
pmon(mtmp);
return(1);
}
mnexto(mtmp) /* Make monster mtmp next to you (if possible) */
struct monst *mtmp;
{
extern coord enexto();
coord mm;
mm = enexto(u.ux, u.uy);
mtmp->mx = mm.x;
mtmp->my = mm.y;
pmon(mtmp);
}
ishuman(mtmp) register struct monst *mtmp; {
return(mtmp->data->mlet == '@');
}
setmangry(mtmp) register struct monst *mtmp; {
if(!mtmp->mpeaceful) return;
if(mtmp->mtame) return;
mtmp->mpeaceful = 0;
if(ishuman(mtmp)) pline("%s gets angry!", Monnam(mtmp));
}
/* not one hundred procent correct: now a snake may hide under an
invisible object */
canseemon(mtmp)
register struct monst *mtmp;
{
return((!mtmp->minvis || See_invisible)
&& (!mtmp->mhide || !o_at(mtmp->mx,mtmp->my))
&& cansee(mtmp->mx, mtmp->my));
}