]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.mon.c
1 /* $NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $ */
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * - Neither the name of the Stichting Centrum voor Wiskunde en
20 * Informatica, nor the names of its contributors may be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 #include <sys/cdefs.h>
66 __RCSID("$NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $");
72 #include "hack.mfndpos.h"
74 static int warnlevel
; /* used by movemon and dochugw */
75 static long lastwarntime
;
76 static int lastwarnlev
;
78 static const char *const warnings
[] = {
79 "white", "pink", "red", "ruby", "purple", "black"
82 static int dochugw(struct monst
*);
83 static void mpickgold(struct monst
*);
84 static void mpickgems(struct monst
*);
85 static void dmonsfree(void);
86 static int ishuman(struct monst
*);
97 /* find a monster that we haven't treated yet */
99 * note that mtmp or mtmp->nmon might get killed while mtmp
100 * moves, so we cannot just walk down the chain (even new
101 * monsters might get created!)
103 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
104 if (mtmp
->mlstmv
< moves
)
106 /* treated all monsters */
110 mtmp
->mlstmv
= moves
;
112 /* most monsters drown in pools */
114 boolean inpool
, iseel
;
116 inpool
= (levl
[mtmp
->mx
][mtmp
->my
].typ
== POOL
);
117 iseel
= (mtmp
->data
->mlet
== ';');
118 if (inpool
&& !iseel
) {
119 if (cansee(mtmp
->mx
, mtmp
->my
))
120 pline("%s drowns.", Monnam(mtmp
));
124 /* but eels have a difficult time outside */
125 if (iseel
&& !inpool
) {
132 if (mtmp
->mblinded
&& !--mtmp
->mblinded
)
134 if (mtmp
->mfleetim
&& !--mtmp
->mfleetim
)
138 if (mtmp
->mspeed
!= MSLOW
|| !(moves
% 2)) {
139 /* continue if the monster died fighting */
141 if (Conflict
&& cansee(mtmp
->mx
, mtmp
->my
)
142 && (fr
= fightm(mtmp
)) == 2)
144 if (fr
< 0 && dochugw(mtmp
))
147 if (mtmp
->mspeed
== MFAST
&& dochugw(mtmp
))
151 warnlevel
-= u
.ulevel
;
152 if (warnlevel
>= SIZE(warnings
))
153 warnlevel
= SIZE(warnings
) - 1;
155 if (warnlevel
> lastwarnlev
|| moves
> lastwarntime
+ 5) {
157 switch (Warning
& (LEFT_RING
| RIGHT_RING
)) {
159 rr
= "Your left ring glows";
162 rr
= "Your right ring glows";
164 case LEFT_RING
| RIGHT_RING
:
165 rr
= "Both your rings glow";
168 rr
= "Your fingertips glow";
171 pline("%s %s!", rr
, warnings
[warnlevel
]);
172 lastwarntime
= moves
;
173 lastwarnlev
= warnlevel
;
175 dmonsfree(); /* remove all dead monsters */
179 justswld(struct monst
*mtmp
, const char *name
)
186 kludge("%s swallows you!", name
);
195 youswld(struct monst
*mtmp
, int dam
, unsigned int die
, const char *name
)
197 if (mtmp
!= u
.ustuck
)
199 kludge("%s digests you!", name
);
201 if (u
.uswldtim
++ >= die
) { /* a3 */
202 pline("It totally digests you!");
208 flags
.botlx
= 1; /* should we show status line ? */
213 dochugw(struct monst
*mtmp
)
217 int dead
= dochug(mtmp
);
220 if (!dead
) /* monster still alive */
222 if (!mtmp
->mpeaceful
)
223 if (mtmp
->data
->mlevel
> warnlevel
)
224 if ((dd
= dist(mtmp
->mx
, mtmp
->my
)) < dist(x
, y
))
226 if (!canseemon(mtmp
))
227 warnlevel
= mtmp
->data
->mlevel
;
231 /* returns 1 if monster died moving, 0 otherwise */
233 dochug(struct monst
*mtmp
)
235 const struct permonst
*mdat
;
236 int tmp
= 0, nearby
, scared
;
238 if (mtmp
->cham
&& !rn2(6))
239 (void) newcham(mtmp
, &mons
[dlevel
+ 14 + rn2(CMNUM
- 14 - dlevel
)]);
241 if (mdat
->mlevel
< 0)
242 panic("bad monster %c (%d)", mdat
->mlet
, mdat
->mlevel
);
244 /* regenerate monsters */
245 if ((!(moves
% 20) || strchr(MREGEN
, mdat
->mlet
)) &&
246 mtmp
->mhp
< mtmp
->mhpmax
)
250 return (0); /* frozen monsters don't do anything */
253 /* wake up, or get out of here. */
254 /* ettins are hard to surprise */
255 /* Nymphs and Leprechauns do not easily wake up */
256 if (cansee(mtmp
->mx
, mtmp
->my
) &&
257 (!Stealth
|| (mdat
->mlet
== 'e' && rn2(10))) &&
258 (!strchr("NL", mdat
->mlet
) || !rn2(50)) &&
259 (Aggravate_monster
|| strchr("d1", mdat
->mlet
)
260 || (!rn2(7) && !mtmp
->mimic
)))
265 /* not frozen or sleeping: wipe out texts written in the dust */
266 wipe_engr_at(mtmp
->mx
, mtmp
->my
, 1);
268 /* confused monsters get unconfused with small probability */
269 if (mtmp
->mconf
&& !rn2(50))
272 /* some monsters teleport */
273 if (mtmp
->mflee
&& strchr("tNL", mdat
->mlet
) && !rn2(40)) {
277 if (mdat
->mmove
< rnd(6))
280 /* fleeing monsters might regain courage */
281 if (mtmp
->mflee
&& !mtmp
->mfleetim
282 && mtmp
->mhp
== mtmp
->mhpmax
&& !rn2(25))
285 nearby
= (dist(mtmp
->mx
, mtmp
->my
) < 3);
286 scared
= (nearby
&& (sengr_at("Elbereth", u
.ux
, u
.uy
) ||
287 sobj_at(SCR_SCARE_MONSTER
, u
.ux
, u
.uy
)));
288 if (scared
&& !mtmp
->mflee
) {
290 mtmp
->mfleetim
= (rn2(7) ? rnd(10) : rnd(100));
295 (mtmp
->minvis
&& !rn2(3)) ||
296 (strchr("BIuy", mdat
->mlet
) && !rn2(4)) ||
297 (mdat
->mlet
== 'L' && !u
.ugold
&& (mtmp
->mgold
|| rn2(2))) ||
298 (!mtmp
->mcansee
&& !rn2(4)) ||
301 tmp
= m_move(mtmp
, 0); /* 2: monster died moving */
302 if (tmp
== 2 || (tmp
&& mdat
->mmove
<= 12))
305 if (!strchr("Ea", mdat
->mlet
) && nearby
&&
306 !mtmp
->mpeaceful
&& u
.uhp
> 0 && !scared
) {
308 return (1); /* monster died (e.g. 'y' or 'F') */
310 /* extra movement for fast monsters */
311 if (mdat
->mmove
- 12 > rnd(12))
312 tmp
= m_move(mtmp
, 1);
317 m_move(struct monst
*mtmp
, int after
)
320 int nx
, ny
, omx
, omy
, appr
, nearer
, cnt
, i
, j
;
321 xchar gx
, gy
, nix
, niy
, chcnt
;
323 boolean likegold
= 0, likegems
= 0, likeobjs
= 0;
324 char msym
= mtmp
->data
->mlet
;
325 schar mmoved
= 0; /* not strictly nec.: chi >= 0 will
330 if (mtmp
->mfroz
|| mtmp
->msleep
)
332 if (mtmp
->mtrapped
) {
335 return (2); /* he died */
337 return (0); /* still in trap, so didnt move */
339 if (mtmp
->mhide
&& o_at(mtmp
->mx
, mtmp
->my
) && rn2(10))
340 return (0); /* do not leave hiding place */
347 /* my dog gets a special treatment */
349 return (dog_move(mtmp
, after
));
351 /* likewise for shopkeeper */
353 mmoved
= shk_move(mtmp
);
356 mmoved
= 0; /* follow player outside shop */
358 /* and for the guard */
364 * teleport if that lies in our nature ('t') or when badly wounded
367 if ((msym
== 't' && !rn2(5))
368 || (msym
== '1' && (mtmp
->mhp
< 7 || (!xdnstair
&& !rn2(5))
369 || levl
[u
.ux
][u
.uy
].typ
== STAIRS
))) {
370 if (mtmp
->mhp
< 7 || (msym
== 't' && rn2(2)))
377 /* spit fire ('D') or use a wand ('1') when appropriate */
378 if (strchr("D1", msym
))
381 if (msym
== 'U' && !mtmp
->mcan
&& canseemon(mtmp
) &&
382 mtmp
->mcansee
&& rn2(5)) {
384 pline("%s's gaze has confused you!", Monnam(mtmp
));
386 pline("You are getting more and more confused.");
389 Confusion
+= d(3, 4); /* timeout */
392 if (!mtmp
->mflee
&& u
.uswallow
&& u
.ustuck
!= mtmp
)
397 if (mtmp
->mconf
|| Invis
|| !mtmp
->mcansee
||
398 (strchr("BIy", msym
) && !rn2(3)))
404 if (msym
== 'L' && appr
== 1 && mtmp
->mgold
> u
.ugold
)
408 * random criterion for 'smell' or track finding ability should use
409 * mtmp->msmell or sth
412 ('a' <= msym
&& msym
<= 'z')) {
415 mroom
= inroom(omx
, omy
);
416 if (mroom
< 0 || mroom
!= inroom(u
.ux
, u
.uy
)) {
417 cp
= gettrack(omx
, omy
);
424 /* look for gold or jewels nearby */
425 likegold
= (strchr("LOD", msym
) != NULL
);
426 likegems
= (strchr("ODu", msym
) != NULL
);
427 likeobjs
= mtmp
->mhide
;
428 #define SRCHRADIUS 25
430 xchar mind
= SRCHRADIUS
; /* not too far away */
434 for (gold
= fgold
; gold
; gold
= gold
->ngold
)
435 if ((dd
= DIST(omx
, omy
, gold
->gx
, gold
->gy
)) < mind
) {
441 if (likegems
|| likeobjs
) {
443 for (otmp
= fobj
; otmp
; otmp
= otmp
->nobj
)
444 if (likeobjs
|| otmp
->olet
== GEM_SYM
)
446 objects
[otmp
->otyp
].g_val
!= 0)
447 if ((dd
= DIST(omx
, omy
, otmp
->ox
, otmp
->oy
)) < mind
) {
453 if (mind
< SRCHRADIUS
&& appr
== -1) {
454 if (dist(omx
, omy
) < 10) {
463 cnt
= mfndpos(mtmp
, poss
, info
,
464 msym
== 'u' ? NOTONL
:
465 (msym
== '@' || msym
== '1') ? (ALLOW_SSM
| ALLOW_TRAPS
) :
466 strchr(UNDEAD
, msym
) ? NOGARLIC
: ALLOW_TRAPS
);
467 /* ALLOW_ROCK for some monsters ? */
470 for (i
= 0; i
< cnt
; i
++) {
473 for (j
= 0; j
< MTSZ
&& j
< cnt
- 1; j
++)
474 if (nx
== mtmp
->mtrack
[j
].x
&& ny
== mtmp
->mtrack
[j
].y
)
475 if (rn2(4 * (cnt
- j
)))
478 /* some stupid compilers think that this is too complicated */
480 int d1
= DIST(nx
, ny
, gx
, gy
);
481 int d2
= DIST(nix
, niy
, gx
, gy
);
485 nearer
= (DIST(nx
, ny
, gx
, gy
) < DIST(nix
, niy
, gx
, gy
));
487 if ((appr
== 1 && nearer
) || (appr
== -1 && !nearer
) ||
489 (!appr
&& !rn2(++chcnt
))) {
498 if (info
[chi
] & ALLOW_M
) {
499 mtmp2
= m_at(nix
, niy
);
501 panic("error in m_move");
502 if (hitmm(mtmp
, mtmp2
) == 1 && rn2(4) &&
503 hitmm(mtmp2
, mtmp
) == 2)
507 if (info
[chi
] & ALLOW_U
) {
508 (void) hitu(mtmp
, d(mtmp
->data
->damn
, mtmp
->data
->damd
) + 1);
513 for (j
= MTSZ
- 1; j
> 0; j
--)
514 mtmp
->mtrack
[j
] = mtmp
->mtrack
[j
- 1];
515 mtmp
->mtrack
[0].x
= omx
;
516 mtmp
->mtrack
[0].y
= omy
;
522 if (msym
== 'u' && rn2(2)) {
533 if (mintrap(mtmp
) == 2) /* he died */
540 mtmp
->mundetected
= 1;
547 mpickgold(struct monst
*mtmp
)
550 while ((gold
= g_at(mtmp
->mx
, mtmp
->my
)) != NULL
) {
551 mtmp
->mgold
+= gold
->amount
;
553 if (levl
[mtmp
->mx
][mtmp
->my
].scrsym
== '$')
554 newsym(mtmp
->mx
, mtmp
->my
);
559 mpickgems(struct monst
*mtmp
)
562 for (otmp
= fobj
; otmp
; otmp
= otmp
->nobj
)
563 if (otmp
->olet
== GEM_SYM
)
564 if (otmp
->ox
== mtmp
->mx
&& otmp
->oy
== mtmp
->my
)
565 if (mtmp
->data
->mlet
!= 'u' || objects
[otmp
->otyp
].g_val
!= 0) {
567 mpickobj(mtmp
, otmp
);
568 if (levl
[mtmp
->mx
][mtmp
->my
].scrsym
== GEM_SYM
)
569 newsym(mtmp
->mx
, mtmp
->my
); /* %% */
570 return; /* pick only one object */
574 /* return number of acceptable neighbour positions */
576 mfndpos(struct monst
*mon
, coord poss
[9], int info
[9], int flag
)
578 int x
, y
, nx
, ny
, cnt
= 0, ntyp
;
585 nowtyp
= levl
[x
][y
].typ
;
587 pool
= (mon
->data
->mlet
== ';');
588 nexttry
: /* eels prefer the water, but if there is no
589 * water nearby, they will crawl over land */
594 for (nx
= x
- 1; nx
<= x
+ 1; nx
++)
595 for (ny
= y
- 1; ny
<= y
+ 1; ny
++)
596 if (nx
!= x
|| ny
!= y
)
598 if (!IS_ROCK(ntyp
= levl
[nx
][ny
].typ
))
599 if (!(nx
!= x
&& ny
!= y
&& (nowtyp
== DOOR
|| ntyp
== DOOR
)))
600 if ((ntyp
== POOL
) == pool
) {
602 if (nx
== u
.ux
&& ny
== u
.uy
) {
603 if (!(flag
& ALLOW_U
))
606 } else if ((mtmp
= m_at(nx
, ny
)) != NULL
) {
607 if (!(flag
& ALLOW_M
))
611 if (!(flag
& ALLOW_TM
))
613 info
[cnt
] |= ALLOW_TM
;
616 if (sobj_at(CLOVE_OF_GARLIC
, nx
, ny
)) {
619 info
[cnt
] |= NOGARLIC
;
621 if (sobj_at(SCR_SCARE_MONSTER
, nx
, ny
) ||
622 (!mon
->mpeaceful
&& sengr_at("Elbereth", nx
, ny
))) {
623 if (!(flag
& ALLOW_SSM
))
625 info
[cnt
] |= ALLOW_SSM
;
627 if (sobj_at(ENORMOUS_ROCK
, nx
, ny
)) {
628 if (!(flag
& ALLOW_ROCK
))
630 info
[cnt
] |= ALLOW_ROCK
;
632 if (!Invis
&& online(nx
, ny
)) {
645 struct trap
*ttmp
= t_at(nx
, ny
);
648 tt
= 1 << ttmp
->ttyp
;
649 if (mon
->mtrapseen
& tt
) {
660 if (!cnt
&& pool
&& nowtyp
!= POOL
) {
670 return ((x
- u
.ux
) * (x
- u
.ux
) + (y
- u
.uy
) * (y
- u
.uy
));
674 poisoned(const char *string
, const char *pname
)
679 pline("It was poisoned.");
681 pline("The %s was poisoned!", string
);
682 if (Poison_resistance
) {
683 pline("The poison doesn't seem to affect you.");
689 pline("I am afraid the poison was deadly ...");
693 losehp(rn1(10, 6), pname
);
702 mondead(struct monst
*mtmp
)
719 /* called when monster is moved to larger structure */
721 replmon(struct monst
*mtmp
, struct monst
*mtmp2
)
727 if (u
.ustuck
== mtmp
)
730 replshk(mtmp
, mtmp2
);
736 relmon(struct monst
*mon
)
743 for (mtmp
= fmon
; mtmp
->nmon
!= mon
; mtmp
= mtmp
->nmon
);
744 mtmp
->nmon
= mon
->nmon
;
749 * we do not free monsters immediately, in order to have their name available
750 * shortly after their demise
752 static struct monst
*fdmon
; /* chain of dead monsters, need not to be
756 monfree(struct monst
*mtmp
)
766 while ((mtmp
= fdmon
) != NULL
) {
773 unstuck(struct monst
*mtmp
)
775 if (u
.ustuck
== mtmp
) {
788 killed(struct monst
*mtmp
)
794 const struct permonst
*mdat
;
797 mtmp
->data
= PM_CHAMELEON
;
800 pline("You destroy it!");
802 pline("You destroy %s!",
803 mtmp
->mtame
? amonnam(mtmp
, "poor") : monnam(mtmp
));
807 pline("Your hands stop glowing blue.");
810 /* count killed monsters */
812 nk
= 1; /* in case we cannot find it in mons */
813 tmp
= mdat
- mons
; /* strchr in mons array (if not 'd', '@', ...) */
814 if (tmp
>= 0 && tmp
< CMNUM
+ 2) {
816 if ((nk
= u
.nr_killed
[tmp
]) > MAXMONNO
&&
817 !strchr(fut_geno
, mdat
->mlet
))
818 charcat(fut_geno
, mdat
->mlet
);
820 /* punish bad behaviour */
821 if (mdat
->mlet
== '@')
822 Telepat
= 0, u
.uluck
-= 2;
823 if (mtmp
->mpeaceful
|| mtmp
->mtame
)
825 if (mdat
->mlet
== 'u')
827 if ((int) u
.uluck
< LUCKMIN
)
830 /* give experience points */
831 tmp
= 1 + mdat
->mlevel
* mdat
->mlevel
;
833 tmp
+= 2 * (7 - mdat
->ac
);
834 if (strchr("AcsSDXaeRTVWU&In:P", mdat
->mlet
))
835 tmp
+= 2 * mdat
->mlevel
;
836 if (strchr("DeV&P", mdat
->mlet
))
837 tmp
+= (7 * mdat
->mlevel
);
838 if (mdat
->mlevel
> 6)
840 if (mdat
->mlet
== ';')
845 * ------- recent addition: make nr of points decrease when this is
846 * not the first of this kind
850 int ml
= mdat
->mlevel
;
853 if (ul
< 14) /* points are given based on present and
855 for (tmp2
= 0; !tmp2
|| ul
+ tmp2
<= ml
; tmp2
++)
856 if (u
.uexp
+ 1 + (tmp
+ ((tmp2
<= 0) ? 0 : 4 << (tmp2
- 1))) / nk
857 >= 10 * pow((unsigned) (ul
- 1)))
862 tmp
= (tmp
+ ((tmp2
< 0) ? 0 : 4 << tmp2
)) / nk
;
866 /* note: ul is not necessarily the future value of u.ulevel */
867 /* ------- end of recent valuation change ------- */
868 #endif /* NEW_SCORING */
870 more_experienced(tmp
, 0);
872 while (u
.ulevel
< 14 && u
.uexp
>= newuexp()) {
873 pline("Welcome to experience level %u.", ++u
.ulevel
);
882 /* dispose of monster and make cadaver */
887 if (tmp
== 'm') { /* he killed a minotaur, give him a wand of
889 /* note: the dead minotaur will be on top of it! */
890 mksobj_at(WAN_DIGGING
, x
, y
);
891 /* if(cansee(x,y)) atl(x,y,fobj->olet); */
896 mksobj_at(WORM_TOOTH
, x
, y
);
900 if (!letter(tmp
) || (!strchr("mw", tmp
) && !rn2(3)))
903 if (ACCESSIBLE(levl
[x
][y
].typ
)) /* might be mimic in wall or dead eel */
904 if (x
!= u
.ux
|| y
!= u
.uy
) /* might be here after
906 if (strchr("NTVm&", mdat
->mlet
) || rn2(5)) {
907 struct obj
*obj2
= mkobj_at(tmp
, x
, y
);
909 atl(x
, y
, obj2
->olet
);
915 kludge(const char *str
, const char *arg
)
928 { /* force all chameleons to become normal */
931 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
934 (void) newcham(mtmp
, PM_CHAMELEON
);
938 /* make a chameleon look like a new monster */
939 /* returns 1 if the monster actually changed */
941 newcham(struct monst
*mtmp
, const struct permonst
*mdat
)
945 if (mdat
== mtmp
->data
)
946 return (0); /* still the same monster */
949 wormdead(mtmp
); /* throw tail away */
951 if (u
.ustuck
== mtmp
) {
962 hpd
= (mtmp
->data
->mlevel
) * 8;
966 mhp
= (mdat
->mlevel
) * 8;
967 /* new hp: same fraction of max as before */
968 mtmp
->mhp
= 2 + (hpn
* mhp
) / hpd
;
970 mtmp
->mhpmax
= 2 + (hpn
* mhp
) / hpd
;
971 mtmp
->minvis
= (mdat
->mlet
== 'I') ? 1 : 0;
973 if (mdat
->mlet
== 'w' && getwn(mtmp
))
975 /* perhaps we should clear mtmp->mtame here? */
977 unpmon(mtmp
); /* necessary for 'I' and to force pmon */
982 /* Make monster mtmp next to you (if possible) */
984 mnexto(struct monst
*mtmp
)
987 mm
= enexto(u
.ux
, u
.uy
);
994 ishuman(struct monst
*mtmp
)
996 return (mtmp
->data
->mlet
== '@');
1000 setmangry(struct monst
*mtmp
)
1002 if (!mtmp
->mpeaceful
)
1006 mtmp
->mpeaceful
= 0;
1008 pline("%s gets angry!", Monnam(mtmp
));
1012 * not one hundred procent correct: now a snake may hide under an invisible
1016 canseemon(struct monst
*mtmp
)
1018 return ((!mtmp
->minvis
|| See_invisible
)
1019 && (!mtmp
->mhide
|| !o_at(mtmp
->mx
, mtmp
->my
))
1020 && cansee(mtmp
->mx
, mtmp
->my
));