OSDN Git Service

add gitignore
[nethackexpress/trunk.git] / src / dog.c
1 /*      SCCS Id: @(#)dog.c      3.4     2002/09/08      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #include "edog.h"
7
8 #ifdef OVLB
9
10 STATIC_DCL int NDECL(pet_type);
11
12 void
13 initedog(mtmp)
14 register struct monst *mtmp;
15 {
16         mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5;
17         mtmp->mpeaceful = 1;
18         mtmp->mavenge = 0;
19         set_malign(mtmp); /* recalc alignment now that it's tamed */
20         mtmp->mleashed = 0;
21         mtmp->meating = 0;
22         EDOG(mtmp)->droptime = 0;
23         EDOG(mtmp)->dropdist = 10000;
24         EDOG(mtmp)->apport = 10;
25         EDOG(mtmp)->whistletime = 0;
26         EDOG(mtmp)->hungrytime = 1000 + monstermoves;
27         EDOG(mtmp)->ogoal.x = -1;       /* force error if used before set */
28         EDOG(mtmp)->ogoal.y = -1;
29         EDOG(mtmp)->abuse = 0;
30         EDOG(mtmp)->revivals = 0;
31         EDOG(mtmp)->mhpmax_penalty = 0;
32         EDOG(mtmp)->killed_by_u = 0;
33 }
34
35 STATIC_OVL int
36 pet_type()
37 {
38         if (urole.petnum != NON_PM)
39             return (urole.petnum);
40         else if (preferred_pet == 'c')
41             return (PM_KITTEN);
42         else if (preferred_pet == 'd')
43             return (PM_LITTLE_DOG);
44         else
45             return (rn2(2) ? PM_KITTEN : PM_LITTLE_DOG);
46 }
47
48 struct monst *
49 make_familiar(otmp,x,y,quietly)
50 register struct obj *otmp;
51 xchar x, y;
52 boolean quietly;
53 {
54         struct permonst *pm;
55         struct monst *mtmp = 0;
56         int chance, trycnt = 100;
57
58         do {
59             if (otmp) { /* figurine; otherwise spell */
60                 int mndx = otmp->corpsenm;
61                 pm = &mons[mndx];
62                 /* activating a figurine provides one way to exceed the
63                    maximum number of the target critter created--unless
64                    it has a special limit (erinys, Nazgul) */
65                 if ((mvitals[mndx].mvflags & G_EXTINCT) &&
66                         mbirth_limit(mndx) != MAXMONNO) {
67                     if (!quietly)
68                         /* have just been given "You <do something with>
69                            the figurine and it transforms." message */
70                         pline("... into a pile of dust.");
71                     break;      /* mtmp is null */
72                 }
73             } else if (!rn2(3)) {
74                 pm = &mons[pet_type()];
75             } else {
76                 pm = rndmonst();
77                 if (!pm) {
78                   if (!quietly)
79                     There("seems to be nothing available for a familiar.");
80                   break;
81                 }
82             }
83
84             mtmp = makemon(pm, x, y, MM_EDOG|MM_IGNOREWATER);
85             if (otmp && !mtmp) { /* monster was genocided or square occupied */
86                 if (!quietly)
87                    pline_The("figurine writhes and then shatters into pieces!");
88                 break;
89             }
90         } while (!mtmp && --trycnt > 0);
91
92         if (!mtmp) return (struct monst *)0;
93
94         if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp))
95                 return (struct monst *)0;
96
97         initedog(mtmp);
98         mtmp->msleeping = 0;
99         if (otmp) { /* figurine; resulting monster might not become a pet */
100             chance = rn2(10);   /* 0==tame, 1==peaceful, 2==hostile */
101             if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2;
102             /* 0,1,2:  b=80%,10,10; nc=10%,80,10; c=10%,10,80 */
103             if (chance > 0) {
104                 mtmp->mtame = 0;        /* not tame after all */
105                 if (chance == 2) { /* hostile (cursed figurine) */
106                     if (!quietly)
107                        You("get a bad feeling about this.");
108                     mtmp->mpeaceful = 0;
109                     set_malign(mtmp);
110                 }
111             }
112             /* if figurine has been named, give same name to the monster */
113             if (otmp->onamelth)
114                 mtmp = christen_monst(mtmp, ONAME(otmp));
115         }
116         set_malign(mtmp); /* more alignment changes */
117         newsym(mtmp->mx, mtmp->my);
118
119         /* must wield weapon immediately since pets will otherwise drop it */
120         if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) {
121                 mtmp->weapon_check = NEED_HTH_WEAPON;
122                 (void) mon_wield_item(mtmp);
123         }
124         return mtmp;
125 }
126
127 struct monst *
128 makedog()
129 {
130         register struct monst *mtmp;
131 #ifdef STEED
132         register struct obj *otmp;
133 #endif
134         const char *petname;
135         int   pettype;
136         static int petname_used = 0;
137
138         if (preferred_pet == 'n') return((struct monst *) 0);
139
140         pettype = pet_type();
141         if (pettype == PM_LITTLE_DOG)
142                 petname = dogname;
143         else if (pettype == PM_PONY)
144                 petname = horsename;
145         else
146                 petname = catname;
147
148         /* default pet names */
149         if (!*petname && pettype == PM_LITTLE_DOG) {
150             /* All of these names were for dogs. */
151             if(Role_if(PM_CAVEMAN)) petname = "Slasher";   /* The Warrior */
152             if(Role_if(PM_SAMURAI)) petname = "Hachi";     /* Shibuya Station */
153             if(Role_if(PM_BARBARIAN)) petname = "Idefix";  /* Obelix */
154             if(Role_if(PM_RANGER)) petname = "Sirius";     /* Orion's dog */
155         }
156
157         mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG);
158
159         if(!mtmp) return((struct monst *) 0); /* pets were genocided */
160
161 #ifdef STEED
162         /* Horses already wear a saddle */
163         if (pettype == PM_PONY && !!(otmp = mksobj(SADDLE, TRUE, FALSE))) {
164             if (mpickobj(mtmp, otmp))
165                 panic("merged saddle?");
166             mtmp->misc_worn_check |= W_SADDLE;
167             otmp->dknown = otmp->bknown = otmp->rknown = 1;
168             otmp->owornmask = W_SADDLE;
169             otmp->leashmon = mtmp->m_id;
170             update_mon_intrinsics(mtmp, otmp, TRUE, TRUE);
171         }
172 #endif
173
174         if (!petname_used++ && *petname)
175                 mtmp = christen_monst(mtmp, petname);
176
177         initedog(mtmp);
178         return(mtmp);
179 }
180
181 /* record `last move time' for all monsters prior to level save so that
182    mon_arrive() can catch up for lost time when they're restored later */
183 void
184 update_mlstmv()
185 {
186         struct monst *mon;
187
188         /* monst->mlstmv used to be updated every time `monst' actually moved,
189            but that is no longer the case so we just do a blanket assignment */
190         for (mon = fmon; mon; mon = mon->nmon)
191             if (!DEADMONSTER(mon)) mon->mlstmv = monstermoves;
192 }
193
194 void
195 losedogs()
196 {
197         register struct monst *mtmp, *mtmp0 = 0, *mtmp2;
198
199         while ((mtmp = mydogs) != 0) {
200                 mydogs = mtmp->nmon;
201                 mon_arrive(mtmp, TRUE);
202         }
203
204         for(mtmp = migrating_mons; mtmp; mtmp = mtmp2) {
205                 mtmp2 = mtmp->nmon;
206                 if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) {
207                     if(mtmp == migrating_mons)
208                         migrating_mons = mtmp->nmon;
209                     else
210                         mtmp0->nmon = mtmp->nmon;
211                     mon_arrive(mtmp, FALSE);
212                 } else
213                     mtmp0 = mtmp;
214         }
215 }
216
217 /* called from resurrect() in addition to losedogs() */
218 void
219 mon_arrive(mtmp, with_you)
220 struct monst *mtmp;
221 boolean with_you;
222 {
223         struct trap *t;
224         xchar xlocale, ylocale, xyloc, xyflags, wander;
225         int num_segs;
226
227         mtmp->nmon = fmon;
228         fmon = mtmp;
229         if (mtmp->isshk)
230             set_residency(mtmp, FALSE);
231
232         num_segs = mtmp->wormno;
233         /* baby long worms have no tail so don't use is_longworm() */
234         if ((mtmp->data == &mons[PM_LONG_WORM]) &&
235 #ifdef DCC30_BUG
236             (mtmp->wormno = get_wormno(), mtmp->wormno != 0))
237 #else
238             (mtmp->wormno = get_wormno()) != 0)
239 #endif
240         {
241             initworm(mtmp, num_segs);
242             /* tail segs are not yet initialized or displayed */
243         } else mtmp->wormno = 0;
244
245         /* some monsters might need to do something special upon arrival
246            _after_ the current level has been fully set up; see dochug() */
247         mtmp->mstrategy |= STRAT_ARRIVE;
248
249         /* make sure mnexto(rloc_to(set_apparxy())) doesn't use stale data */
250         mtmp->mux = u.ux,  mtmp->muy = u.uy;
251         xyloc   = mtmp->mtrack[0].x;
252         xyflags = mtmp->mtrack[0].y;
253         xlocale = mtmp->mtrack[1].x;
254         ylocale = mtmp->mtrack[1].y;
255         mtmp->mtrack[0].x = mtmp->mtrack[0].y = 0;
256         mtmp->mtrack[1].x = mtmp->mtrack[1].y = 0;
257
258 #ifdef STEED
259         if (mtmp == u.usteed)
260             return;     /* don't place steed on the map */
261 #endif
262         if (with_you) {
263             /* When a monster accompanies you, sometimes it will arrive
264                at your intended destination and you'll end up next to
265                that spot.  This code doesn't control the final outcome;
266                goto_level(do.c) decides who ends up at your target spot
267                when there is a monster there too. */
268             if (!MON_AT(u.ux, u.uy) &&
269                     !rn2(mtmp->mtame ? 10 : mtmp->mpeaceful ? 5 : 2))
270                 rloc_to(mtmp, u.ux, u.uy);
271             else
272                 mnexto(mtmp);
273             return;
274         }
275         /*
276          * The monster arrived on this level independently of the player.
277          * Its coordinate fields were overloaded for use as flags that
278          * specify its final destination.
279          */
280
281         if (mtmp->mlstmv < monstermoves - 1L) {
282             /* heal monster for time spent in limbo */
283             long nmv = monstermoves - 1L - mtmp->mlstmv;
284
285             mon_catchup_elapsed_time(mtmp, nmv);
286             mtmp->mlstmv = monstermoves - 1L;
287
288             /* let monster move a bit on new level (see placement code below) */
289             wander = (xchar) min(nmv, 8);
290         } else
291             wander = 0;
292
293         switch (xyloc) {
294          case MIGR_APPROX_XY:   /* {x,y}locale set above */
295                 break;
296          case MIGR_EXACT_XY:    wander = 0;
297                 break;
298          case MIGR_NEAR_PLAYER: xlocale = u.ux,  ylocale = u.uy;
299                 break;
300          case MIGR_STAIRS_UP:   xlocale = xupstair,  ylocale = yupstair;
301                 break;
302          case MIGR_STAIRS_DOWN: xlocale = xdnstair,  ylocale = ydnstair;
303                 break;
304          case MIGR_LADDER_UP:   xlocale = xupladder,  ylocale = yupladder;
305                 break;
306          case MIGR_LADDER_DOWN: xlocale = xdnladder,  ylocale = ydnladder;
307                 break;
308          case MIGR_SSTAIRS:     xlocale = sstairs.sx,  ylocale = sstairs.sy;
309                 break;
310          case MIGR_PORTAL:
311                 if (In_endgame(&u.uz)) {
312                     /* there is no arrival portal for endgame levels */
313                     /* BUG[?]: for simplicity, this code relies on the fact
314                        that we know that the current endgame levels always
315                        build upwards and never have any exclusion subregion
316                        inside their TELEPORT_REGION settings. */
317                     xlocale = rn1(updest.hx - updest.lx + 1, updest.lx);
318                     ylocale = rn1(updest.hy - updest.ly + 1, updest.ly);
319                     break;
320                 }
321                 /* find the arrival portal */
322                 for (t = ftrap; t; t = t->ntrap)
323                     if (t->ttyp == MAGIC_PORTAL) break;
324                 if (t) {
325                     xlocale = t->tx,  ylocale = t->ty;
326                     break;
327                 } else {
328                     impossible("mon_arrive: no corresponding portal?");
329                 } /*FALLTHRU*/
330          default:
331          case MIGR_RANDOM:      xlocale = ylocale = 0;
332                     break;
333             }
334
335         if (xlocale && wander) {
336             /* monster moved a bit; pick a nearby location */
337             /* mnearto() deals w/stone, et al */
338             char *r = in_rooms(xlocale, ylocale, 0);
339             if (r && *r) {
340                 coord c;
341                 /* somexy() handles irregular rooms */
342                 if (somexy(&rooms[*r - ROOMOFFSET], &c))
343                     xlocale = c.x,  ylocale = c.y;
344                 else
345                     xlocale = ylocale = 0;
346             } else {            /* not in a room */
347                 int i, j;
348                 i = max(1, xlocale - wander);
349                 j = min(COLNO-1, xlocale + wander);
350                 xlocale = rn1(j - i, i);
351                 i = max(0, ylocale - wander);
352                 j = min(ROWNO-1, ylocale + wander);
353                 ylocale = rn1(j - i, i);
354             }
355         }       /* moved a bit */
356
357         mtmp->mx = 0;   /*(already is 0)*/
358         mtmp->my = xyflags;
359         if (xlocale)
360             (void) mnearto(mtmp, xlocale, ylocale, FALSE);
361         else {
362             if (!rloc(mtmp,TRUE)) {
363                 /*
364                  * Failed to place migrating monster,
365                  * probably because the level is full.
366                  * Dump the monster's cargo and leave the monster dead.
367                  */
368                 struct obj *obj, *corpse;
369                 while ((obj = mtmp->minvent) != 0) {
370                     obj_extract_self(obj);
371                     obj_no_longer_held(obj);
372                     if (obj->owornmask & W_WEP)
373                         setmnotwielded(mtmp,obj);
374                     obj->owornmask = 0L;
375                     if (xlocale && ylocale)
376                             place_object(obj, xlocale, ylocale);
377                     else {
378                         rloco(obj);
379                         get_obj_location(obj, &xlocale, &ylocale, 0);
380                     }
381                 }
382                 corpse = mkcorpstat(CORPSE, (struct monst *)0, mtmp->data,
383                                 xlocale, ylocale, FALSE);
384 #ifndef GOLDOBJ
385                 if (mtmp->mgold) {
386                     if (xlocale == 0 && ylocale == 0 && corpse) {
387                         (void) get_obj_location(corpse, &xlocale, &ylocale, 0);
388                         (void) mkgold(mtmp->mgold, xlocale, ylocale);
389                     }
390                     mtmp->mgold = 0L;
391                 }
392 #endif
393                 mongone(mtmp);
394             }
395         }
396 }
397
398 /* heal monster for time spent elsewhere */
399 void
400 mon_catchup_elapsed_time(mtmp, nmv)
401 struct monst *mtmp;
402 long nmv;               /* number of moves */
403 {
404         int imv = 0;    /* avoid zillions of casts and lint warnings */
405
406 #if defined(DEBUG) || defined(BETA)
407         if (nmv < 0L) {                 /* crash likely... */
408             panic("catchup from future time?");
409             /*NOTREACHED*/
410             return;
411         } else if (nmv == 0L) {         /* safe, but should'nt happen */
412             impossible("catchup from now?");
413         } else
414 #endif
415         if (nmv >= LARGEST_INT)         /* paranoia */
416             imv = LARGEST_INT - 1;
417         else
418             imv = (int)nmv;
419
420         /* might stop being afraid, blind or frozen */
421         /* set to 1 and allow final decrement in movemon() */
422         if (mtmp->mblinded) {
423             if (imv >= (int) mtmp->mblinded) mtmp->mblinded = 1;
424             else mtmp->mblinded -= imv;
425         }
426         if (mtmp->mfrozen) {
427             if (imv >= (int) mtmp->mfrozen) mtmp->mfrozen = 1;
428             else mtmp->mfrozen -= imv;
429         }
430         if (mtmp->mfleetim) {
431             if (imv >= (int) mtmp->mfleetim) mtmp->mfleetim = 1;
432             else mtmp->mfleetim -= imv;
433         }
434
435         /* might recover from temporary trouble */
436         if (mtmp->mtrapped && rn2(imv + 1) > 40/2) mtmp->mtrapped = 0;
437         if (mtmp->mconf    && rn2(imv + 1) > 50/2) mtmp->mconf = 0;
438         if (mtmp->mstun    && rn2(imv + 1) > 10/2) mtmp->mstun = 0;
439
440         /* might finish eating or be able to use special ability again */
441         if (imv > mtmp->meating) mtmp->meating = 0;
442         else mtmp->meating -= imv;
443         if (imv > mtmp->mspec_used) mtmp->mspec_used = 0;
444         else mtmp->mspec_used -= imv;
445
446         /* reduce tameness for every 150 moves you are separated */
447         if (mtmp->mtame) {
448             int wilder = (imv + 75) / 150;
449             if (mtmp->mtame > wilder) mtmp->mtame -= wilder;    /* less tame */
450             else if (mtmp->mtame > rn2(wilder)) mtmp->mtame = 0;  /* untame */
451             else mtmp->mtame = mtmp->mpeaceful = 0;             /* hostile! */
452         }
453         /* check to see if it would have died as a pet; if so, go wild instead
454          * of dying the next time we call dog_move()
455          */
456         if (mtmp->mtame && !mtmp->isminion &&
457                         (carnivorous(mtmp->data) || herbivorous(mtmp->data))) {
458             struct edog *edog = EDOG(mtmp);
459
460             if ((monstermoves > edog->hungrytime + 500 && mtmp->mhp < 3) ||
461                     (monstermoves > edog->hungrytime + 750))
462                 mtmp->mtame = mtmp->mpeaceful = 0;
463         }
464
465         if (!mtmp->mtame && mtmp->mleashed) {
466             /* leashed monsters should always be with hero, consequently
467                never losing any time to be accounted for later */
468             impossible("catching up for leashed monster?");
469             m_unleash(mtmp, FALSE);
470         }
471
472         /* recover lost hit points */
473         if (!regenerates(mtmp->data)) imv /= 20;
474         if (mtmp->mhp + imv >= mtmp->mhpmax)
475             mtmp->mhp = mtmp->mhpmax;
476         else mtmp->mhp += imv;
477 }
478
479 #endif /* OVLB */
480 #ifdef OVL2
481
482 /* called when you move to another level */
483 void
484 keepdogs(pets_only)
485 boolean pets_only;      /* true for ascension or final escape */
486 {
487         register struct monst *mtmp, *mtmp2;
488         register struct obj *obj;
489         int num_segs;
490         boolean stay_behind;
491
492         for (mtmp = fmon; mtmp; mtmp = mtmp2) {
493             mtmp2 = mtmp->nmon;
494             if (DEADMONSTER(mtmp)) continue;
495             if (pets_only && !mtmp->mtame) continue;
496             if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) ||
497 #ifdef STEED
498                         (mtmp == u.usteed) ||
499 #endif
500                 /* the wiz will level t-port from anywhere to chase
501                    the amulet; if you don't have it, will chase you
502                    only if in range. -3. */
503                         (u.uhave.amulet && mtmp->iswiz))
504                 && ((!mtmp->msleeping && mtmp->mcanmove)
505 #ifdef STEED
506                     /* eg if level teleport or new trap, steed has no control
507                        to avoid following */
508                     || (mtmp == u.usteed)
509 #endif
510                     )
511                 /* monster won't follow if it hasn't noticed you yet */
512                 && !(mtmp->mstrategy & STRAT_WAITFORU)) {
513                 stay_behind = FALSE;
514                 if (mtmp->mtame && mtmp->meating) {
515                         if (canseemon(mtmp))
516                             pline("%s is still eating.", Monnam(mtmp));
517                         stay_behind = TRUE;
518                 } else if (mon_has_amulet(mtmp)) {
519                         if (canseemon(mtmp))
520                             pline("%s seems very disoriented for a moment.",
521                                 Monnam(mtmp));
522                         stay_behind = TRUE;
523                 } else if (mtmp->mtame && mtmp->mtrapped) {
524                         if (canseemon(mtmp))
525                             pline("%s is still trapped.", Monnam(mtmp));
526                         stay_behind = TRUE;
527                 }
528 #ifdef STEED
529                 if (mtmp == u.usteed) stay_behind = FALSE;
530 #endif
531                 if (stay_behind) {
532                         if (mtmp->mleashed) {
533                                 pline("%s leash suddenly comes loose.",
534                                         humanoid(mtmp->data)
535                                             ? (mtmp->female ? "Her" : "His")
536                                             : "Its");
537                                 m_unleash(mtmp, FALSE);
538                         }
539                         continue;
540                 }
541                 if (mtmp->isshk)
542                         set_residency(mtmp, TRUE);
543
544                 if (mtmp->wormno) {
545                     register int cnt;
546                     /* NOTE: worm is truncated to # segs = max wormno size */
547                     cnt = count_wsegs(mtmp);
548                     num_segs = min(cnt, MAX_NUM_WORMS - 1);
549                     wormgone(mtmp);
550                 } else num_segs = 0;
551
552                 /* set minvent's obj->no_charge to 0 */
553                 for(obj = mtmp->minvent; obj; obj = obj->nobj) {
554                     if (Has_contents(obj))
555                         picked_container(obj);  /* does the right thing */
556                     obj->no_charge = 0;
557                 }
558
559                 relmon(mtmp);
560                 newsym(mtmp->mx,mtmp->my);
561                 mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */
562                 mtmp->wormno = num_segs;
563                 mtmp->mlstmv = monstermoves;
564                 mtmp->nmon = mydogs;
565                 mydogs = mtmp;
566             } else if (mtmp->iswiz) {
567                 /* we want to be able to find him when his next resurrection
568                    chance comes up, but have him resume his present location
569                    if player returns to this level before that time */
570                 migrate_to_level(mtmp, ledger_no(&u.uz),
571                                  MIGR_EXACT_XY, (coord *)0);
572             } else if (mtmp->mleashed) {
573                 /* this can happen if your quest leader ejects you from the
574                    "home" level while a leashed pet isn't next to you */
575                 pline("%s leash goes slack.", s_suffix(Monnam(mtmp)));
576                 m_unleash(mtmp, FALSE);
577             }
578         }
579 }
580
581 #endif /* OVL2 */
582 #ifdef OVLB
583
584 void
585 migrate_to_level(mtmp, tolev, xyloc, cc)
586         register struct monst *mtmp;
587         xchar tolev;    /* destination level */
588         xchar xyloc;    /* MIGR_xxx destination xy location: */
589         coord *cc;      /* optional destination coordinates */
590 {
591         register struct obj *obj;
592         d_level new_lev;
593         xchar xyflags;
594         int num_segs = 0;       /* count of worm segments */
595
596         if (mtmp->isshk)
597             set_residency(mtmp, TRUE);
598
599         if (mtmp->wormno) {
600             register int cnt;
601           /* **** NOTE: worm is truncated to # segs = max wormno size **** */
602             cnt = count_wsegs(mtmp);
603             num_segs = min(cnt, MAX_NUM_WORMS - 1);
604             wormgone(mtmp);
605         }
606
607         /* set minvent's obj->no_charge to 0 */
608         for(obj = mtmp->minvent; obj; obj = obj->nobj) {
609             if (Has_contents(obj))
610                 picked_container(obj);  /* does the right thing */
611             obj->no_charge = 0;
612         }
613
614         if (mtmp->mleashed) {
615                 mtmp->mtame--;
616                 m_unleash(mtmp, TRUE);
617         }
618         relmon(mtmp);
619         mtmp->nmon = migrating_mons;
620         migrating_mons = mtmp;
621         newsym(mtmp->mx,mtmp->my);
622
623         new_lev.dnum = ledger_to_dnum((xchar)tolev);
624         new_lev.dlevel = ledger_to_dlev((xchar)tolev);
625         /* overload mtmp->[mx,my], mtmp->[mux,muy], and mtmp->mtrack[] as */
626         /* destination codes (setup flag bits before altering mx or my) */
627         xyflags = (depth(&new_lev) < depth(&u.uz));     /* 1 => up */
628         if (In_W_tower(mtmp->mx, mtmp->my, &u.uz)) xyflags |= 2;
629         mtmp->wormno = num_segs;
630         mtmp->mlstmv = monstermoves;
631         mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx;
632         mtmp->mtrack[1].y = cc ? cc->y : mtmp->my;
633         mtmp->mtrack[0].x = xyloc;
634         mtmp->mtrack[0].y = xyflags;
635         mtmp->mux = new_lev.dnum;
636         mtmp->muy = new_lev.dlevel;
637         mtmp->mx = mtmp->my = 0;        /* this implies migration */
638 }
639
640 #endif /* OVLB */
641 #ifdef OVL1
642
643 /* return quality of food; the lower the better */
644 /* fungi will eat even tainted food */
645 int
646 dogfood(mon,obj)
647 struct monst *mon;
648 register struct obj *obj;
649 {
650         boolean carni = carnivorous(mon->data);
651         boolean herbi = herbivorous(mon->data);
652         struct permonst *fptr = &mons[obj->corpsenm];
653         boolean starving;
654
655         if (is_quest_artifact(obj) || obj_resists(obj, 0, 95))
656             return (obj->cursed ? TABU : APPORT);
657
658         switch(obj->oclass) {
659         case FOOD_CLASS:
660             if (obj->otyp == CORPSE &&
661                 ((touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
662                  || is_rider(fptr)))
663                     return TABU;
664
665             /* Ghouls only eat old corpses... yum! */
666             if (mon->data == &mons[PM_GHOUL])
667                 return (obj->otyp == CORPSE &&
668                         peek_at_iced_corpse_age(obj) + 50L <= monstermoves) ?
669                                 DOGFOOD : TABU;
670
671             if (!carni && !herbi)
672                     return (obj->cursed ? UNDEF : APPORT);
673
674             /* a starving pet will eat almost anything */
675             starving = (mon->mtame && !mon->isminion &&
676                         EDOG(mon)->mhpmax_penalty);
677
678             switch (obj->otyp) {
679                 case TRIPE_RATION:
680                 case MEATBALL:
681                 case MEAT_RING:
682                 case MEAT_STICK:
683                 case HUGE_CHUNK_OF_MEAT:
684                     return (carni ? DOGFOOD : MANFOOD);
685                 case EGG:
686                     if (touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
687                         return POISON;
688                     return (carni ? CADAVER : MANFOOD);
689                 case CORPSE:
690                    if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves
691                                             && obj->corpsenm != PM_LIZARD
692                                             && obj->corpsenm != PM_LICHEN
693                                             && mon->data->mlet != S_FUNGUS) ||
694                         (acidic(&mons[obj->corpsenm]) && !resists_acid(mon)) ||
695                         (poisonous(&mons[obj->corpsenm]) &&
696                                                 !resists_poison(mon)))
697                         return POISON;
698                     else if (vegan(fptr))
699                         return (herbi ? CADAVER : MANFOOD);
700                     else return (carni ? CADAVER : MANFOOD);
701                 case CLOVE_OF_GARLIC:
702                     return (is_undead(mon->data) ? TABU :
703                             ((herbi || starving) ? ACCFOOD : MANFOOD));
704                 case TIN:
705                     return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
706                 case APPLE:
707                 case CARROT:
708                     return (herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD);
709                 case BANANA:
710                     return ((mon->data->mlet == S_YETI) ? DOGFOOD :
711                             ((herbi || starving) ? ACCFOOD : MANFOOD));
712                 default:
713                     if (starving) return ACCFOOD;
714                     return (obj->otyp > SLIME_MOLD ?
715                             (carni ? ACCFOOD : MANFOOD) :
716                             (herbi ? ACCFOOD : MANFOOD));
717             }
718         default:
719             if (obj->otyp == AMULET_OF_STRANGULATION ||
720                         obj->otyp == RIN_SLOW_DIGESTION)
721                 return TABU;
722             if (hates_silver(mon->data) &&
723                 objects[obj->otyp].oc_material == SILVER)
724                 return(TABU);
725             if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
726                 return(ACCFOOD);
727             if (metallivorous(mon->data) && is_metallic(obj) && (is_rustprone(obj) || mon->data != &mons[PM_RUST_MONSTER])) {
728                 /* Non-rustproofed ferrous based metals are preferred. */
729                 return((is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD :
730                         ACCFOOD);
731             }
732             if(!obj->cursed && obj->oclass != BALL_CLASS &&
733                                                 obj->oclass != CHAIN_CLASS)
734                 return(APPORT);
735             /* fall into next case */
736         case ROCK_CLASS:
737             return(UNDEF);
738         }
739 }
740
741 #endif /* OVL1 */
742 #ifdef OVLB
743
744 struct monst *
745 tamedog(mtmp, obj)
746 register struct monst *mtmp;
747 register struct obj *obj;
748 {
749         register struct monst *mtmp2;
750
751         /* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */
752         if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA]
753                                 || (mtmp->data->mflags3 & M3_WANTSARTI))
754                 return((struct monst *)0);
755
756         /* worst case, at least it'll be peaceful. */
757         mtmp->mpeaceful = 1;
758         set_malign(mtmp);
759         if(flags.moonphase == FULL_MOON && night() && rn2(6) && obj
760                                                 && mtmp->data->mlet == S_DOG)
761                 return((struct monst *)0);
762
763         /* If we cannot tame it, at least it's no longer afraid. */
764         mtmp->mflee = 0;
765         mtmp->mfleetim = 0;
766
767         /* make grabber let go now, whether it becomes tame or not */
768         if (mtmp == u.ustuck) {
769             if (u.uswallow)
770                 expels(mtmp, mtmp->data, TRUE);
771             else if (!(Upolyd && sticks(youmonst.data)))
772                 unstuck(mtmp);
773         }
774
775         /* feeding it treats makes it tamer */
776         if (mtmp->mtame && obj) {
777             int tasty;
778
779             if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating &&
780                 ((tasty = dogfood(mtmp, obj)) == DOGFOOD ||
781                  (tasty <= ACCFOOD && EDOG(mtmp)->hungrytime <= monstermoves))) {
782                 /* pet will "catch" and eat this thrown food */
783                 if (canseemon(mtmp)) {
784                     boolean big_corpse = (obj->otyp == CORPSE &&
785                                           obj->corpsenm >= LOW_PM &&
786                                 mons[obj->corpsenm].msize > mtmp->data->msize);
787                     pline("%s catches %s%s",
788                           Monnam(mtmp), the(xname(obj)),
789                           !big_corpse ? "." : ", or vice versa!");
790                 } else if (cansee(mtmp->mx,mtmp->my))
791                     pline("%s.", Tobjnam(obj, "stop"));
792                 /* dog_eat expects a floor object */
793                 place_object(obj, mtmp->mx, mtmp->my);
794                 (void) dog_eat(mtmp, obj, mtmp->mx, mtmp->my, FALSE);
795                 /* eating might have killed it, but that doesn't matter here;
796                    a non-null result suppresses "miss" message for thrown
797                    food and also implies that the object has been deleted */
798                 return mtmp;
799             } else
800                 return (struct monst *)0;
801         }
802
803         if (mtmp->mtame || !mtmp->mcanmove ||
804             /* monsters with conflicting structures cannot be tamed */
805             mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion ||
806             is_covetous(mtmp->data) || is_human(mtmp->data) ||
807             (is_demon(mtmp->data) && !is_demon(youmonst.data)) ||
808             (obj && dogfood(mtmp, obj) >= MANFOOD)) return (struct monst *)0;
809
810         if (mtmp->m_id == quest_status.leader_m_id)
811             return((struct monst *)0);
812
813         /* make a new monster which has the pet extension */
814         mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
815         *mtmp2 = *mtmp;
816         mtmp2->mxlth = sizeof(struct edog);
817         if (mtmp->mnamelth) Strcpy(NAME(mtmp2), NAME(mtmp));
818         initedog(mtmp2);
819         replmon(mtmp, mtmp2);
820         /* `mtmp' is now obsolete */
821
822         if (obj) {              /* thrown food */
823             /* defer eating until the edog extension has been set up */
824             place_object(obj, mtmp2->mx, mtmp2->my);    /* put on floor */
825             /* devour the food (might grow into larger, genocided monster) */
826             if (dog_eat(mtmp2, obj, mtmp2->mx, mtmp2->my, TRUE) == 2)
827                 return mtmp2;           /* oops, it died... */
828             /* `obj' is now obsolete */
829         }
830
831         newsym(mtmp2->mx, mtmp2->my);
832         if (attacktype(mtmp2->data, AT_WEAP)) {
833                 mtmp2->weapon_check = NEED_HTH_WEAPON;
834                 (void) mon_wield_item(mtmp2);
835         }
836         return(mtmp2);
837 }
838
839 /*
840  * Called during pet revival or pet life-saving.
841  * If you killed the pet, it revives wild.
842  * If you abused the pet a lot while alive, it revives wild.
843  * If you abused the pet at all while alive, it revives untame.
844  * If the pet wasn't abused and was very tame, it might revive tame.
845  */
846 void
847 wary_dog(mtmp, was_dead)
848 struct monst *mtmp;
849 boolean was_dead;
850 {
851     struct edog *edog;
852     boolean quietly = was_dead;
853
854     mtmp->meating = 0;
855     if (!mtmp->mtame) return;
856     edog = !mtmp->isminion ? EDOG(mtmp) : 0;
857
858     /* if monster was starving when it died, undo that now */
859     if (edog && edog->mhpmax_penalty) {
860         mtmp->mhpmax += edog->mhpmax_penalty;
861         mtmp->mhp += edog->mhpmax_penalty;      /* heal it */
862         edog->mhpmax_penalty = 0;
863     }
864
865     if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) {
866         mtmp->mpeaceful = mtmp->mtame = 0;
867         if (edog->abuse >= 0 && edog->abuse < 10)
868             if (!rn2(edog->abuse + 1)) mtmp->mpeaceful = 1;
869         if(!quietly && cansee(mtmp->mx, mtmp->my)) {
870             if (haseyes(youmonst.data)) {
871                 if (haseyes(mtmp->data))
872                         pline("%s %s to look you in the %s.",
873                                 Monnam(mtmp),
874                                 mtmp->mpeaceful ? "seems unable" :
875                                             "refuses",
876                                 body_part(EYE));
877                 else 
878                         pline("%s avoids your gaze.",
879                                 Monnam(mtmp));
880             }
881         }
882     } else {
883         /* chance it goes wild anyway - Pet Semetary */
884         if (!rn2(mtmp->mtame)) {
885             mtmp->mpeaceful = mtmp->mtame = 0;
886         }
887     }
888     if (!mtmp->mtame) {
889         newsym(mtmp->mx, mtmp->my);
890         /* a life-saved monster might be leashed;
891            don't leave it that way if it's no longer tame */
892         if (mtmp->mleashed) m_unleash(mtmp, TRUE);
893     }
894
895     /* if its still a pet, start a clean pet-slate now */
896     if (edog && mtmp->mtame) {
897         edog->revivals++;
898         edog->killed_by_u = 0;
899         edog->abuse = 0;
900         edog->ogoal.x = edog->ogoal.y = -1;
901         if (was_dead || edog->hungrytime < monstermoves + 500L)
902             edog->hungrytime = monstermoves + 500L;
903         if (was_dead) {
904             edog->droptime = 0L;
905             edog->dropdist = 10000;
906             edog->whistletime = 0L;
907             edog->apport = 5;
908         } /* else lifesaved, so retain current values */
909     }
910 }
911
912 void
913 abuse_dog(mtmp)
914 struct monst *mtmp;
915 {
916         if (!mtmp->mtame) return;
917
918         if (Aggravate_monster || Conflict) mtmp->mtame /=2;
919         else mtmp->mtame--;
920
921         if (mtmp->mtame && !mtmp->isminion)
922             EDOG(mtmp)->abuse++;
923
924         if (!mtmp->mtame && mtmp->mleashed)
925             m_unleash(mtmp, TRUE);
926
927         /* don't make a sound if pet is in the middle of leaving the level */
928         /* newsym isn't necessary in this case either */
929         if (mtmp->mx != 0) {
930             if (mtmp->mtame && rn2(mtmp->mtame)) yelp(mtmp);
931             else growl(mtmp);   /* give them a moment's worry */
932         
933             if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
934         }
935 }
936
937 #endif /* OVLB */
938
939 /*dog.c*/