]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.mon.c
2 * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985.
6 static char rcsid
[] = "$NetBSD: hack.mon.c,v 1.3 1995/03/23 08:30:57 cgd Exp $";
10 #include "hack.mfndpos.h"
13 #define NULL (char *) 0
16 extern struct monst
*makemon();
17 extern struct obj
*mkobj_at();
19 int warnlevel
; /* used by movemon and dochugw */
23 "white", "pink", "red", "ruby", "purple", "black"
28 register struct monst
*mtmp
;
34 /* find a monster that we haven't treated yet */
35 /* note that mtmp or mtmp->nmon might get killed
36 while mtmp moves, so we cannot just walk down the
37 chain (even new monsters might get created!) */
38 for(mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
39 if(mtmp
->mlstmv
< moves
) goto next_mon
;
40 /* treated all monsters */
46 /* most monsters drown in pools */
47 { boolean inpool
, iseel
;
49 inpool
= (levl
[mtmp
->mx
][mtmp
->my
].typ
== POOL
);
50 iseel
= (mtmp
->data
->mlet
== ';');
51 if(inpool
&& !iseel
) {
52 if(cansee(mtmp
->mx
,mtmp
->my
))
53 pline("%s drowns.", Monnam(mtmp
));
57 /* but eels have a difficult time outside */
58 if(iseel
&& !inpool
) {
59 if(mtmp
->mhp
> 1) mtmp
->mhp
--;
64 if(mtmp
->mblinded
&& !--mtmp
->mblinded
)
66 if(mtmp
->mfleetim
&& !--mtmp
->mfleetim
)
68 if(mtmp
->mimic
) continue;
69 if(mtmp
->mspeed
!= MSLOW
|| !(moves%2
)){
70 /* continue if the monster died fighting */
72 if(Conflict
&& cansee(mtmp
->mx
,mtmp
->my
)
73 && (fr
= fightm(mtmp
)) == 2)
75 if(fr
<0 && dochugw(mtmp
))
78 if(mtmp
->mspeed
== MFAST
&& dochugw(mtmp
))
82 warnlevel
-= u
.ulevel
;
83 if(warnlevel
>= SIZE(warnings
))
84 warnlevel
= SIZE(warnings
)-1;
86 if(warnlevel
> lastwarnlev
|| moves
> lastwarntime
+ 5){
88 switch(Warning
& (LEFT_RING
| RIGHT_RING
)){
90 rr
= "Your left ring glows";
93 rr
= "Your right ring glows";
95 case LEFT_RING
| RIGHT_RING
:
96 rr
= "Both your rings glow";
99 rr
= "Your fingertips glow";
102 pline("%s %s!", rr
, warnings
[warnlevel
]);
103 lastwarntime
= moves
;
104 lastwarnlev
= warnlevel
;
107 dmonsfree(); /* remove all dead monsters */
111 register struct monst
*mtmp
;
119 kludge("%s swallows you!",name
);
127 youswld(mtmp
,dam
,die
,name
)
128 register struct monst
*mtmp
;
132 if(mtmp
!= u
.ustuck
) return;
133 kludge("%s digests you!",name
);
135 if(u
.uswldtim
++ >= die
){ /* a3 */
136 pline("It totally digests you!");
139 if(u
.uhp
< 1) done_in_by(mtmp
);
140 /* flags.botlx = 1; /* should we show status line ? */
143 dochugw(mtmp
) register struct monst
*mtmp
; {
144 register x
= mtmp
->mx
;
145 register y
= mtmp
->my
;
146 register d
= dochug(mtmp
);
148 if(!d
) /* monster still alive */
151 if(mtmp
->data
->mlevel
> warnlevel
)
152 if((dd
= dist(mtmp
->mx
,mtmp
->my
)) < dist(x
,y
))
155 warnlevel
= mtmp
->data
->mlevel
;
159 /* returns 1 if monster died moving, 0 otherwise */
161 register struct monst
*mtmp
;
163 register struct permonst
*mdat
;
164 register tmp
, nearby
, scared
;
166 if(mtmp
->cham
&& !rn2(6))
167 (void) newcham(mtmp
, &mons
[dlevel
+14+rn2(CMNUM
-14-dlevel
)]);
170 panic("bad monster %c (%d)",mdat
->mlet
,mdat
->mlevel
);
172 /* regenerate monsters */
173 if((!(moves%20
) || index(MREGEN
, mdat
->mlet
)) &&
174 mtmp
->mhp
< mtmp
->mhpmax
)
177 if(mtmp
->mfroz
) return(0); /* frozen monsters don't do anything */
180 /* wake up, or get out of here. */
181 /* ettins are hard to surprise */
182 /* Nymphs and Leprechauns do not easily wake up */
183 if(cansee(mtmp
->mx
,mtmp
->my
) &&
184 (!Stealth
|| (mdat
->mlet
== 'e' && rn2(10))) &&
185 (!index("NL",mdat
->mlet
) || !rn2(50)) &&
186 (Aggravate_monster
|| index("d1", mdat
->mlet
)
187 || (!rn2(7) && !mtmp
->mimic
)))
192 /* not frozen or sleeping: wipe out texts written in the dust */
193 wipe_engr_at(mtmp
->mx
, mtmp
->my
, 1);
195 /* confused monsters get unconfused with small probability */
196 if(mtmp
->mconf
&& !rn2(50)) mtmp
->mconf
= 0;
198 /* some monsters teleport */
199 if(mtmp
->mflee
&& index("tNL", mdat
->mlet
) && !rn2(40)){
203 if(mdat
->mmove
< rnd(6)) return(0);
205 /* fleeing monsters might regain courage */
206 if(mtmp
->mflee
&& !mtmp
->mfleetim
207 && mtmp
->mhp
== mtmp
->mhpmax
&& !rn2(25))
210 nearby
= (dist(mtmp
->mx
, mtmp
->my
) < 3);
211 scared
= (nearby
&& (sengr_at("Elbereth", u
.ux
, u
.uy
) ||
212 sobj_at(SCR_SCARE_MONSTER
, u
.ux
, u
.uy
)));
213 if(scared
&& !mtmp
->mflee
) {
215 mtmp
->mfleetim
= (rn2(7) ? rnd(10) : rnd(100));
221 (mtmp
->minvis
&& !rn2(3)) ||
222 (index("BIuy", mdat
->mlet
) && !rn2(4)) ||
223 (mdat
->mlet
== 'L' && !u
.ugold
&& (mtmp
->mgold
|| rn2(2))) ||
224 (!mtmp
->mcansee
&& !rn2(4)) ||
227 tmp
= m_move(mtmp
,0); /* 2: monster died moving */
228 if(tmp
== 2 || (tmp
&& mdat
->mmove
<= 12))
232 if(!index("Ea", mdat
->mlet
) && nearby
&&
233 !mtmp
->mpeaceful
&& u
.uhp
> 0 && !scared
) {
235 return(1); /* monster died (e.g. 'y' or 'F') */
237 /* extra movement for fast monsters */
238 if(mdat
->mmove
-12 > rnd(12)) tmp
= m_move(mtmp
,1);
243 register struct monst
*mtmp
;
245 register struct monst
*mtmp2
;
246 register nx
,ny
,omx
,omy
,appr
,nearer
,cnt
,i
,j
;
247 xchar gx
,gy
,nix
,niy
,chcnt
;
249 boolean likegold
, likegems
, likeobjs
;
250 char msym
= mtmp
->data
->mlet
;
251 schar mmoved
= 0; /* not strictly nec.: chi >= 0 will do */
255 if(mtmp
->mfroz
|| mtmp
->msleep
)
259 if(i
== 2) return(2); /* he died */
260 if(i
== 1) return(0); /* still in trap, so didnt move */
262 if(mtmp
->mhide
&& o_at(mtmp
->mx
,mtmp
->my
) && rn2(10))
263 return(0); /* do not leave hiding place */
270 /* my dog gets a special treatment */
272 return( dog_move(mtmp
, after
) );
275 /* likewise for shopkeeper */
277 mmoved
= shk_move(mtmp
);
280 mmoved
= 0; /* follow player outside shop */
283 /* and for the guard */
289 /* teleport if that lies in our nature ('t') or when badly wounded ('1') */
290 if((msym
== 't' && !rn2(5))
291 || (msym
== '1' && (mtmp
->mhp
< 7 || (!xdnstair
&& !rn2(5))
292 || levl
[u
.ux
][u
.uy
].typ
== STAIRS
))) {
293 if(mtmp
->mhp
< 7 || (msym
== 't' && rn2(2)))
301 /* spit fire ('D') or use a wand ('1') when appropriate */
302 if(index("D1", msym
))
305 if(msym
== 'U' && !mtmp
->mcan
&& canseemon(mtmp
) &&
306 mtmp
->mcansee
&& rn2(5)) {
308 pline("%s's gaze has confused you!", Monnam(mtmp
));
310 pline("You are getting more and more confused.");
311 if(rn2(3)) mtmp
->mcan
= 1;
312 Confusion
+= d(3,4); /* timeout */
315 if(!mtmp
->mflee
&& u
.uswallow
&& u
.ustuck
!= mtmp
) return(1);
317 if(mtmp
->mflee
) appr
= -1;
318 if(mtmp
->mconf
|| Invis
|| !mtmp
->mcansee
||
319 (index("BIy", msym
) && !rn2(3)))
325 if(msym
== 'L' && appr
== 1 && mtmp
->mgold
> u
.ugold
)
328 /* random criterion for 'smell' or track finding ability
329 should use mtmp->msmell or sth
332 ('a' <= msym
&& msym
<= 'z')) {
333 extern coord
*gettrack();
336 mroom
= inroom(omx
,omy
);
337 if(mroom
< 0 || mroom
!= inroom(u
.ux
,u
.uy
)){
338 cp
= gettrack(omx
,omy
);
346 /* look for gold or jewels nearby */
347 likegold
= (index("LOD", msym
) != NULL
);
348 likegems
= (index("ODu", msym
) != NULL
);
349 likeobjs
= mtmp
->mhide
;
350 #define SRCHRADIUS 25
351 { xchar mind
= SRCHRADIUS
; /* not too far away */
354 register struct gold
*gold
;
355 for(gold
= fgold
; gold
; gold
= gold
->ngold
)
356 if((dd
= DIST(omx
,omy
,gold
->gx
,gold
->gy
)) < mind
){
362 if(likegems
|| likeobjs
){
363 register struct obj
*otmp
;
364 for(otmp
= fobj
; otmp
; otmp
= otmp
->nobj
)
365 if(likeobjs
|| otmp
->olet
== GEM_SYM
)
367 objects
[otmp
->otyp
].g_val
!= 0)
368 if((dd
= DIST(omx
,omy
,otmp
->ox
,otmp
->oy
)) < mind
){
374 if(mind
< SRCHRADIUS
&& appr
== -1) {
375 if(dist(omx
,omy
) < 10) {
384 cnt
= mfndpos(mtmp
,poss
,info
,
385 msym
== 'u' ? NOTONL
:
386 (msym
== '@' || msym
== '1') ? (ALLOW_SSM
| ALLOW_TRAPS
) :
387 index(UNDEAD
, msym
) ? NOGARLIC
: ALLOW_TRAPS
);
388 /* ALLOW_ROCK for some monsters ? */
391 for(i
=0; i
<cnt
; i
++) {
394 for(j
=0; j
<MTSZ
&& j
<cnt
-1; j
++)
395 if(nx
== mtmp
->mtrack
[j
].x
&& ny
== mtmp
->mtrack
[j
].y
)
396 if(rn2(4*(cnt
-j
))) goto nxti
;
398 /* some stupid compilers think that this is too complicated */
399 { int d1
= DIST(nx
,ny
,gx
,gy
);
400 int d2
= DIST(nix
,niy
,gx
,gy
);
404 nearer
= (DIST(nx
,ny
,gx
,gy
) < DIST(nix
,niy
,gx
,gy
));
406 if((appr
== 1 && nearer
) || (appr
== -1 && !nearer
) ||
408 (!appr
&& !rn2(++chcnt
))){
417 if(info
[chi
] & ALLOW_M
){
418 mtmp2
= m_at(nix
,niy
);
419 if(hitmm(mtmp
,mtmp2
) == 1 && rn2(4) &&
420 hitmm(mtmp2
,mtmp
) == 2) return(2);
423 if(info
[chi
] & ALLOW_U
){
424 (void) hitu(mtmp
, d(mtmp
->data
->damn
, mtmp
->data
->damd
)+1);
429 for(j
=MTSZ
-1; j
>0; j
--) mtmp
->mtrack
[j
] = mtmp
->mtrack
[j
-1];
430 mtmp
->mtrack
[0].x
= omx
;
431 mtmp
->mtrack
[0].y
= omy
;
433 if(mtmp
->wormno
) worm_move(mtmp
);
436 if(msym
== 'u' && rn2(2)){
441 if(mtmp
->wormno
) worm_nomove(mtmp
);
446 if(mintrap(mtmp
) == 2) /* he died */
448 if(likegold
) mpickgold(mtmp
);
449 if(likegems
) mpickgems(mtmp
);
450 if(mtmp
->mhide
) mtmp
->mundetected
= 1;
456 mpickgold(mtmp
) register struct monst
*mtmp
; {
457 register struct gold
*gold
;
458 while(gold
= g_at(mtmp
->mx
, mtmp
->my
)){
459 mtmp
->mgold
+= gold
->amount
;
461 if(levl
[mtmp
->mx
][mtmp
->my
].scrsym
== '$')
462 newsym(mtmp
->mx
, mtmp
->my
);
466 mpickgems(mtmp
) register struct monst
*mtmp
; {
467 register struct obj
*otmp
;
468 for(otmp
= fobj
; otmp
; otmp
= otmp
->nobj
)
469 if(otmp
->olet
== GEM_SYM
)
470 if(otmp
->ox
== mtmp
->mx
&& otmp
->oy
== mtmp
->my
)
471 if(mtmp
->data
->mlet
!= 'u' || objects
[otmp
->otyp
].g_val
!= 0){
473 mpickobj(mtmp
, otmp
);
474 if(levl
[mtmp
->mx
][mtmp
->my
].scrsym
== GEM_SYM
)
475 newsym(mtmp
->mx
, mtmp
->my
); /* %% */
476 return; /* pick only one object */
480 /* return number of acceptable neighbour positions */
481 mfndpos(mon
,poss
,info
,flag
)
482 register struct monst
*mon
;
486 register int x
,y
,nx
,ny
,cnt
= 0,ntyp
;
487 register struct monst
*mtmp
;
493 nowtyp
= levl
[x
][y
].typ
;
495 pool
= (mon
->data
->mlet
== ';');
496 nexttry
: /* eels prefer the water, but if there is no water nearby,
497 they will crawl over land */
502 for(nx
= x
-1; nx
<= x
+1; nx
++) for(ny
= y
-1; ny
<= y
+1; ny
++)
503 if(nx
!= x
|| ny
!= y
) if(isok(nx
,ny
))
504 if(!IS_ROCK(ntyp
= levl
[nx
][ny
].typ
))
505 if(!(nx
!= x
&& ny
!= y
&& (nowtyp
== DOOR
|| ntyp
== DOOR
)))
506 if((ntyp
== POOL
) == pool
) {
508 if(nx
== u
.ux
&& ny
== u
.uy
){
509 if(!(flag
& ALLOW_U
)) continue;
511 } else if(mtmp
= m_at(nx
,ny
)){
512 if(!(flag
& ALLOW_M
)) continue;
515 if(!(flag
& ALLOW_TM
)) continue;
516 info
[cnt
] |= ALLOW_TM
;
519 if(sobj_at(CLOVE_OF_GARLIC
, nx
, ny
)) {
520 if(flag
& NOGARLIC
) continue;
521 info
[cnt
] |= NOGARLIC
;
523 if(sobj_at(SCR_SCARE_MONSTER
, nx
, ny
) ||
524 (!mon
->mpeaceful
&& sengr_at("Elbereth", nx
, ny
))) {
525 if(!(flag
& ALLOW_SSM
)) continue;
526 info
[cnt
] |= ALLOW_SSM
;
528 if(sobj_at(ENORMOUS_ROCK
, nx
, ny
)) {
529 if(!(flag
& ALLOW_ROCK
)) continue;
530 info
[cnt
] |= ALLOW_ROCK
;
532 if(!Invis
&& online(nx
,ny
)){
533 if(flag
& NOTONL
) continue;
536 /* we cannot avoid traps of an unknown kind */
537 { register struct trap
*ttmp
= t_at(nx
, ny
);
540 tt
= 1 << ttmp
->ttyp
;
541 if(mon
->mtrapseen
& tt
){
542 if(!(flag
& tt
)) continue;
551 if(!cnt
&& pool
&& nowtyp
!= POOL
) {
559 return((x
-u
.ux
)*(x
-u
.ux
) + (y
-u
.uy
)*(y
-u
.uy
));
562 poisoned(string
, pname
)
563 register char *string
, *pname
;
567 if(Blind
) pline("It was poisoned.");
568 else pline("The %s was poisoned!",string
);
569 if(Poison_resistance
) {
570 pline("The poison doesn't seem to affect you.");
576 pline("I am afraid the poison was deadly ...");
580 losehp(rn1(10,6), pname
);
589 register struct monst
*mtmp
;
595 if(mtmp
->isshk
) shkdead(mtmp
);
596 if(mtmp
->isgd
) gddead();
598 if(mtmp
->wormno
) wormdead(mtmp
);
603 /* called when monster is moved to larger structure */
605 register struct monst
*mtmp
, *mtmp2
;
611 if(u
.ustuck
== mtmp
) u
.ustuck
= mtmp2
;
612 if(mtmp2
->isshk
) replshk(mtmp
,mtmp2
);
613 if(mtmp2
->isgd
) replgd(mtmp
,mtmp2
);
617 register struct monst
*mon
;
619 register struct monst
*mtmp
;
621 if(mon
== fmon
) fmon
= fmon
->nmon
;
623 for(mtmp
= fmon
; mtmp
->nmon
!= mon
; mtmp
= mtmp
->nmon
) ;
624 mtmp
->nmon
= mon
->nmon
;
628 /* we do not free monsters immediately, in order to have their name
629 available shortly after their demise */
630 struct monst
*fdmon
; /* chain of dead monsters, need not to be saved */
632 monfree(mtmp
) register struct monst
*mtmp
; {
638 register struct monst
*mtmp
;
646 register struct monst
*mtmp
;
648 if(u
.ustuck
== mtmp
) {
661 register struct monst
*mtmp
;
666 register int tmp
,tmp2
,nk
,x
,y
;
667 register struct permonst
*mdat
;
668 extern long newuexp();
670 if(mtmp
->cham
) mtmp
->data
= PM_CHAMELEON
;
672 if(Blind
) pline("You destroy it!");
674 pline("You destroy %s!",
675 mtmp
->mtame
? amonnam(mtmp
, "poor") : monnam(mtmp
));
678 if(!Blind
) pline("Your hands stop glowing blue.");
682 /* count killed monsters */
684 nk
= 1; /* in case we cannot find it in mons */
685 tmp
= mdat
- mons
; /* index in mons array (if not 'd', '@', ...) */
686 if(tmp
>= 0 && tmp
< CMNUM
+2) {
687 extern char fut_geno
[];
689 if((nk
= u
.nr_killed
[tmp
]) > MAXMONNO
&&
690 !index(fut_geno
, mdat
->mlet
))
691 charcat(fut_geno
, mdat
->mlet
);
694 /* punish bad behaviour */
695 if(mdat
->mlet
== '@') Telepat
= 0, u
.uluck
-= 2;
696 if(mtmp
->mpeaceful
|| mtmp
->mtame
) u
.uluck
--;
697 if(mdat
->mlet
== 'u') u
.uluck
-= 5;
698 if((int)u
.uluck
< LUCKMIN
) u
.uluck
= LUCKMIN
;
700 /* give experience points */
701 tmp
= 1 + mdat
->mlevel
* mdat
->mlevel
;
702 if(mdat
->ac
< 3) tmp
+= 2*(7 - mdat
->ac
);
703 if(index("AcsSDXaeRTVWU&In:P", mdat
->mlet
))
704 tmp
+= 2*mdat
->mlevel
;
705 if(index("DeV&P",mdat
->mlet
)) tmp
+= (7*mdat
->mlevel
);
706 if(mdat
->mlevel
> 6) tmp
+= 50;
707 if(mdat
->mlet
== ';') tmp
+= 1000;
710 /* ------- recent addition: make nr of points decrease
711 when this is not the first of this kind */
713 int ml
= mdat
->mlevel
;
715 if(ul
< 14) /* points are given based on present and future level */
716 for(tmp2
= 0; !tmp2
|| ul
+ tmp2
<= ml
; tmp2
++)
717 if(u
.uexp
+ 1 + (tmp
+ ((tmp2
<= 0) ? 0 : 4<<(tmp2
-1)))/nk
718 >= 10*pow((unsigned)(ul
-1)))
719 if(++ul
== 14) break;
722 tmp
= (tmp
+ ((tmp2
< 0) ? 0 : 4<<tmp2
))/nk
;
725 /* note: ul is not necessarily the future value of u.ulevel */
726 /* ------- end of recent valuation change ------- */
729 more_experienced(tmp
,0);
731 while(u
.ulevel
< 14 && u
.uexp
>= newuexp()){
732 pline("Welcome to experience level %u.", ++u
.ulevel
);
734 if(tmp
< 3) tmp
= rnd(10);
740 /* dispose of monster and make cadaver */
741 x
= mtmp
->mx
; y
= mtmp
->my
;
744 if(tmp
== 'm') { /* he killed a minotaur, give him a wand of digging */
745 /* note: the dead minotaur will be on top of it! */
746 mksobj_at(WAN_DIGGING
, x
, y
);
747 /* if(cansee(x,y)) atl(x,y,fobj->olet); */
752 mksobj_at(WORM_TOOTH
, x
, y
);
756 if(!letter(tmp
) || (!index("mw", tmp
) && !rn2(3))) tmp
= 0;
758 if(ACCESSIBLE(levl
[x
][y
].typ
)) /* might be mimic in wall or dead eel*/
759 if(x
!= u
.ux
|| y
!= u
.uy
) /* might be here after swallowed */
760 if(index("NTVm&",mdat
->mlet
) || rn2(5)) {
761 register struct obj
*obj2
= mkobj_at(tmp
,x
,y
);
769 register char *str
,*arg
;
772 if(*str
== '%') pline(str
,"It");
773 else pline(str
,"it");
774 } else pline(str
,arg
);
777 rescham() /* force all chameleons to become normal */
779 register struct monst
*mtmp
;
781 for(mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
784 (void) newcham(mtmp
, PM_CHAMELEON
);
788 newcham(mtmp
,mdat
) /* make a chameleon look like a new monster */
789 /* returns 1 if the monster actually changed */
790 register struct monst
*mtmp
;
791 register struct permonst
*mdat
;
793 register mhp
, hpn
, hpd
;
795 if(mdat
== mtmp
->data
) return(0); /* still the same monster */
797 if(mtmp
->wormno
) wormdead(mtmp
); /* throw tail away */
799 if (u
.ustuck
== mtmp
) {
810 hpd
= (mtmp
->data
->mlevel
)*8;
813 mhp
= (mdat
->mlevel
)*8;
814 /* new hp: same fraction of max as before */
815 mtmp
->mhp
= 2 + (hpn
*mhp
)/hpd
;
817 mtmp
->mhpmax
= 2 + (hpn
*mhp
)/hpd
;
818 mtmp
->minvis
= (mdat
->mlet
== 'I') ? 1 : 0;
820 if(mdat
->mlet
== 'w' && getwn(mtmp
)) initworm(mtmp
);
821 /* perhaps we should clear mtmp->mtame here? */
823 unpmon(mtmp
); /* necessary for 'I' and to force pmon */
828 mnexto(mtmp
) /* Make monster mtmp next to you (if possible) */
831 extern coord
enexto();
833 mm
= enexto(u
.ux
, u
.uy
);
839 ishuman(mtmp
) register struct monst
*mtmp
; {
840 return(mtmp
->data
->mlet
== '@');
843 setmangry(mtmp
) register struct monst
*mtmp
; {
844 if(!mtmp
->mpeaceful
) return;
845 if(mtmp
->mtame
) return;
847 if(ishuman(mtmp
)) pline("%s gets angry!", Monnam(mtmp
));
850 /* not one hundred procent correct: now a snake may hide under an
853 register struct monst
*mtmp
;
855 return((!mtmp
->minvis
|| See_invisible
)
856 && (!mtmp
->mhide
|| !o_at(mtmp
->mx
,mtmp
->my
))
857 && cansee(mtmp
->mx
, mtmp
->my
));