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