Source:NetHack 3.6.0/src/dog.c

From NetHackWiki
(Redirected from Source:Dog.c)
Jump to: navigation, search

Below is the full text to dog.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/dog.c#line123]], for example.

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

Top of file

  1.  /* NetHack 3.6	dog.c	$NHDT-Date: 1446808440 2015/11/06 11:14:00 $  $NHDT-Branch: master $:$NHDT-Revision: 1.52 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  
  7.  STATIC_DCL int NDECL(pet_type);
  8.  

newedog

  1.  void
  2.  newedog(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      if (!mtmp->mextra)
  6.          mtmp->mextra = newmextra();
  7.      if (!EDOG(mtmp)) {
  8.          EDOG(mtmp) = (struct edog *) alloc(sizeof(struct edog));
  9.          (void) memset((genericptr_t) EDOG(mtmp), 0, sizeof(struct edog));
  10.      }
  11.  }
  12.  

free_edog

  1.  void
  2.  free_edog(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      if (mtmp->mextra && EDOG(mtmp)) {
  6.          free((genericptr_t) EDOG(mtmp));
  7.          EDOG(mtmp) = (struct edog *) 0;
  8.      }
  9.      mtmp->mtame = 0;
  10.  }
  11.  

initedog

  1.  void
  2.  initedog(mtmp)
  3.  register struct monst *mtmp;
  4.  {
  5.      mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5;
  6.      mtmp->mpeaceful = 1;
  7.      mtmp->mavenge = 0;
  8.      set_malign(mtmp); /* recalc alignment now that it's tamed */
  9.      mtmp->mleashed = 0;
  10.      mtmp->meating = 0;
  11.      EDOG(mtmp)->droptime = 0;
  12.      EDOG(mtmp)->dropdist = 10000;
  13.      EDOG(mtmp)->apport = 10;
  14.      EDOG(mtmp)->whistletime = 0;
  15.      EDOG(mtmp)->hungrytime = 1000 + monstermoves;
  16.      EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */
  17.      EDOG(mtmp)->ogoal.y = -1;
  18.      EDOG(mtmp)->abuse = 0;
  19.      EDOG(mtmp)->revivals = 0;
  20.      EDOG(mtmp)->mhpmax_penalty = 0;
  21.      EDOG(mtmp)->killed_by_u = 0;
  22.  }
  23.  

pet_type

  1.  STATIC_OVL int
  2.  pet_type()
  3.  {
  4.      if (urole.petnum != NON_PM)
  5.          return  urole.petnum;
  6.      else if (preferred_pet == 'c')
  7.          return  PM_KITTEN;
  8.      else if (preferred_pet == 'd')
  9.          return  PM_LITTLE_DOG;
  10.      else
  11.          return  rn2(2) ? PM_KITTEN : PM_LITTLE_DOG;
  12.  }
  13.  

make_familiar

  1.  struct monst *
  2.  make_familiar(otmp, x, y, quietly)
  3.  register struct obj *otmp;
  4.  xchar x, y;
  5.  boolean quietly;
  6.  {
  7.      struct permonst *pm;
  8.      struct monst *mtmp = 0;
  9.      int chance, trycnt = 100;
  10.  
  11.      do {
  12.          if (otmp) { /* figurine; otherwise spell */
  13.              int mndx = otmp->corpsenm;
  14.              pm = &mons[mndx];
  15.              /* activating a figurine provides one way to exceed the
  16.                 maximum number of the target critter created--unless
  17.                 it has a special limit (erinys, Nazgul) */
  18.              if ((mvitals[mndx].mvflags & G_EXTINCT)
  19.                  && mbirth_limit(mndx) != MAXMONNO) {
  20.                  if (!quietly)
  21.                      /* have just been given "You <do something with>
  22.                         the figurine and it transforms." message */
  23.                      pline("... into a pile of dust.");
  24.                  break; /* mtmp is null */
  25.              }
  26.          } else if (!rn2(3)) {
  27.              pm = &mons[pet_type()];
  28.          } else {
  29.              pm = rndmonst();
  30.              if (!pm) {
  31.                  if (!quietly)
  32.                      There("seems to be nothing available for a familiar.");
  33.                  break;
  34.              }
  35.          }
  36.  
  37.          mtmp = makemon(pm, x, y, MM_EDOG | MM_IGNOREWATER | NO_MINVENT);
  38.          if (otmp && !mtmp) { /* monster was genocided or square occupied */
  39.              if (!quietly)
  40.                  pline_The("figurine writhes and then shatters into pieces!");
  41.              break;
  42.          }
  43.      } while (!mtmp && --trycnt > 0);
  44.  
  45.      if (!mtmp)
  46.          return (struct monst *) 0;
  47.  
  48.      if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp))
  49.          return (struct monst *) 0;
  50.  
  51.      initedog(mtmp);
  52.      mtmp->msleeping = 0;
  53.      if (otmp) { /* figurine; resulting monster might not become a pet */
  54.          chance = rn2(10); /* 0==tame, 1==peaceful, 2==hostile */
  55.          if (chance > 2)
  56.              chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2;
  57.          /* 0,1,2:  b=80%,10,10; nc=10%,80,10; c=10%,10,80 */
  58.          if (chance > 0) {
  59.              mtmp->mtame = 0;   /* not tame after all */
  60.              if (chance == 2) { /* hostile (cursed figurine) */
  61.                  if (!quietly)
  62.                      You("get a bad feeling about this.");
  63.                  mtmp->mpeaceful = 0;
  64.                  set_malign(mtmp);
  65.              }
  66.          }
  67.          /* if figurine has been named, give same name to the monster */
  68.          if (has_oname(otmp))
  69.              mtmp = christen_monst(mtmp, ONAME(otmp));
  70.      }
  71.      set_malign(mtmp); /* more alignment changes */
  72.      newsym(mtmp->mx, mtmp->my);
  73.  
  74.      /* must wield weapon immediately since pets will otherwise drop it */
  75.      if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) {
  76.          mtmp->weapon_check = NEED_HTH_WEAPON;
  77.          (void) mon_wield_item(mtmp);
  78.      }
  79.      return mtmp;
  80.  }
  81.  

makedog

  1.  struct monst *
  2.  makedog()
  3.  {
  4.      register struct monst *mtmp;
  5.      register struct obj *otmp;
  6.      const char *petname;
  7.      int pettype;
  8.      static int petname_used = 0;
  9.  
  10.      if (preferred_pet == 'n')
  11.          return ((struct monst *) 0);
  12.  
  13.      pettype = pet_type();
  14.      if (pettype == PM_LITTLE_DOG)
  15.          petname = dogname;
  16.      else if (pettype == PM_PONY)
  17.          petname = horsename;
  18.      else
  19.          petname = catname;
  20.  
  21.      /* default pet names */
  22.      if (!*petname && pettype == PM_LITTLE_DOG) {
  23.          /* All of these names were for dogs. */
  24.          if (Role_if(PM_CAVEMAN))
  25.              petname = "Slasher"; /* The Warrior */
  26.          if (Role_if(PM_SAMURAI))
  27.              petname = "Hachi"; /* Shibuya Station */
  28.          if (Role_if(PM_BARBARIAN))
  29.              petname = "Idefix"; /* Obelix */
  30.          if (Role_if(PM_RANGER))
  31.              petname = "Sirius"; /* Orion's dog */
  32.      }
  33.  
  34.      mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG);
  35.  
  36.      if (!mtmp)
  37.          return ((struct monst *) 0); /* pets were genocided */
  38.  
  39.      context.startingpet_mid = mtmp->m_id;
  40.      /* Horses already wear a saddle */
  41.      if (pettype == PM_PONY && !!(otmp = mksobj(SADDLE, TRUE, FALSE))) {
  42.          if (mpickobj(mtmp, otmp))
  43.              panic("merged saddle?");
  44.          mtmp->misc_worn_check |= W_SADDLE;
  45.          otmp->dknown = otmp->bknown = otmp->rknown = 1;
  46.          otmp->owornmask = W_SADDLE;
  47.          otmp->leashmon = mtmp->m_id;
  48.          update_mon_intrinsics(mtmp, otmp, TRUE, TRUE);
  49.      }
  50.  
  51.      if (!petname_used++ && *petname)
  52.          mtmp = christen_monst(mtmp, petname);
  53.  
  54.      initedog(mtmp);
  55.      return  mtmp;
  56.  }
  57.  

update_mlstmv

  1.  /* record `last move time' for all monsters prior to level save so that
  2.     mon_arrive() can catch up for lost time when they're restored later */
  3.  void
  4.  update_mlstmv()
  5.  {
  6.      struct monst *mon;
  7.  
  8.      /* monst->mlstmv used to be updated every time `monst' actually moved,
  9.         but that is no longer the case so we just do a blanket assignment */
  10.      for (mon = fmon; mon; mon = mon->nmon) {
  11.          if (DEADMONSTER(mon))
  12.              continue;
  13.          mon->mlstmv = monstermoves;
  14.      }
  15.  }
  16.  

losedogs

  1.  void
  2.  losedogs()
  3.  {
  4.      register struct monst *mtmp, *mtmp0 = 0, *mtmp2;
  5.      int dismissKops = 0;
  6.  
  7.      /*
  8.       * First, scan migrating_mons for shopkeepers who want to dismiss Kops,
  9.       * and scan mydogs for shopkeepers who want to retain kops.
  10.       * Second, dismiss kops if warranted, making more room for arrival.
  11.       * Third, place monsters accompanying the hero.
  12.       * Last, place migrating monsters coming to this level.
  13.       *
  14.       * Hero might eventually be displaced (due to the third step, but
  15.       * occurring later), which is the main reason to do the second step
  16.       * sooner (in turn necessitating the first step, rather than combining
  17.       * the list scans with monster placement).
  18.       */
  19.  
  20.      /* check for returning shk(s) */
  21.      for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
  22.          if (mtmp->mux != u.uz.dnum || mtmp->muy != u.uz.dlevel)
  23.              continue;
  24.          if (mtmp->isshk) {
  25.              if (ESHK(mtmp)->dismiss_kops) {
  26.                  if (dismissKops == 0)
  27.                      dismissKops = 1;
  28.                  ESHK(mtmp)->dismiss_kops = FALSE; /* reset */
  29.              } else if (!mtmp->mpeaceful) {
  30.                  /* an unpacified shk is returning; don't dismiss kops
  31.                     even if another pacified one is willing to do so */
  32.                  dismissKops = -1;
  33.                  /* [keep looping; later monsters might need ESHK reset] */
  34.              }
  35.          }
  36.      }
  37.      /* make the same check for mydogs */
  38.      for (mtmp = mydogs; mtmp && dismissKops >= 0; mtmp = mtmp->nmon) {
  39.          if (mtmp->isshk) {
  40.              /* hostile shk might accompany hero [ESHK(mtmp)->dismiss_kops
  41.                 can't be set here; it's only used for migrating_mons] */
  42.              if (!mtmp->mpeaceful)
  43.                  dismissKops = -1;
  44.          }
  45.      }
  46.  
  47.      /* when a hostile shopkeeper chases hero to another level
  48.         and then gets paid off there, get rid of summoned kops
  49.         here now that he has returned to his shop level */
  50.      if (dismissKops > 0)
  51.          make_happy_shoppers(TRUE);
  52.  
  53.      /* place pets and/or any other monsters who accompany hero */
  54.      while ((mtmp = mydogs) != 0) {
  55.          mydogs = mtmp->nmon;
  56.          mon_arrive(mtmp, TRUE);
  57.      }
  58.  
  59.      /* time for migrating monsters to arrive */
  60.      for (mtmp = migrating_mons; mtmp; mtmp = mtmp2) {
  61.          mtmp2 = mtmp->nmon;
  62.          if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) {
  63.              if (mtmp == migrating_mons)
  64.                  migrating_mons = mtmp->nmon;
  65.              else
  66.                  mtmp0->nmon = mtmp->nmon;
  67.              mon_arrive(mtmp, FALSE);
  68.          } else
  69.              mtmp0 = mtmp;
  70.      }
  71.  }
  72.  

mon_arrive

  1.  /* called from resurrect() in addition to losedogs() */
  2.  void
  3.  mon_arrive(mtmp, with_you)
  4.  struct monst *mtmp;
  5.  boolean with_you;
  6.  {
  7.      struct trap *t;
  8.      xchar xlocale, ylocale, xyloc, xyflags, wander;
  9.      int num_segs;
  10.  
  11.      mtmp->nmon = fmon;
  12.      fmon = mtmp;
  13.      if (mtmp->isshk)
  14.          set_residency(mtmp, FALSE);
  15.  
  16.      num_segs = mtmp->wormno;
  17.      /* baby long worms have no tail so don't use is_longworm() */
  18.      if (mtmp->data == &mons[PM_LONG_WORM]) {
  19.          mtmp->wormno = get_wormno();
  20.          if (mtmp->wormno)
  21.              initworm(mtmp, num_segs);
  22.      } else
  23.          mtmp->wormno = 0;
  24.  
  25.      /* some monsters might need to do something special upon arrival
  26.         _after_ the current level has been fully set up; see dochug() */
  27.      mtmp->mstrategy |= STRAT_ARRIVE;
  28.  
  29.      /* make sure mnexto(rloc_to(set_apparxy())) doesn't use stale data */
  30.      mtmp->mux = u.ux, mtmp->muy = u.uy;
  31.      xyloc = mtmp->mtrack[0].x;
  32.      xyflags = mtmp->mtrack[0].y;
  33.      xlocale = mtmp->mtrack[1].x;
  34.      ylocale = mtmp->mtrack[1].y;
  35.      mtmp->mtrack[0].x = mtmp->mtrack[0].y = 0;
  36.      mtmp->mtrack[1].x = mtmp->mtrack[1].y = 0;
  37.  
  38.      if (mtmp == u.usteed)
  39.          return; /* don't place steed on the map */
  40.      if (with_you) {
  41.          /* When a monster accompanies you, sometimes it will arrive
  42.             at your intended destination and you'll end up next to
  43.             that spot.  This code doesn't control the final outcome;
  44.             goto_level(do.c) decides who ends up at your target spot
  45.             when there is a monster there too. */
  46.          if (!MON_AT(u.ux, u.uy)
  47.              && !rn2(mtmp->mtame ? 10 : mtmp->mpeaceful ? 5 : 2))
  48.              rloc_to(mtmp, u.ux, u.uy);
  49.          else
  50.              mnexto(mtmp);
  51.          return;
  52.      }
  53.      /*
  54.       * The monster arrived on this level independently of the player.
  55.       * Its coordinate fields were overloaded for use as flags that
  56.       * specify its final destination.
  57.       */
  58.  
  59.      if (mtmp->mlstmv < monstermoves - 1L) {
  60.          /* heal monster for time spent in limbo */
  61.          long nmv = monstermoves - 1L - mtmp->mlstmv;
  62.  
  63.          mon_catchup_elapsed_time(mtmp, nmv);
  64.          mtmp->mlstmv = monstermoves - 1L;
  65.  
  66.          /* let monster move a bit on new level (see placement code below) */
  67.          wander = (xchar) min(nmv, 8);
  68.      } else
  69.          wander = 0;
  70.  
  71.      switch (xyloc) {
  72.      case MIGR_APPROX_XY: /* {x,y}locale set above */
  73.          break;
  74.      case MIGR_EXACT_XY:
  75.          wander = 0;
  76.          break;
  77.      case MIGR_WITH_HERO:
  78.          xlocale = u.ux, ylocale = u.uy;
  79.          break;
  80.      case MIGR_STAIRS_UP:
  81.          xlocale = xupstair, ylocale = yupstair;
  82.          break;
  83.      case MIGR_STAIRS_DOWN:
  84.          xlocale = xdnstair, ylocale = ydnstair;
  85.          break;
  86.      case MIGR_LADDER_UP:
  87.          xlocale = xupladder, ylocale = yupladder;
  88.          break;
  89.      case MIGR_LADDER_DOWN:
  90.          xlocale = xdnladder, ylocale = ydnladder;
  91.          break;
  92.      case MIGR_SSTAIRS:
  93.          xlocale = sstairs.sx, ylocale = sstairs.sy;
  94.          break;
  95.      case MIGR_PORTAL:
  96.          if (In_endgame(&u.uz)) {
  97.              /* there is no arrival portal for endgame levels */
  98.              /* BUG[?]: for simplicity, this code relies on the fact
  99.                 that we know that the current endgame levels always
  100.                 build upwards and never have any exclusion subregion
  101.                 inside their TELEPORT_REGION settings. */
  102.              xlocale = rn1(updest.hx - updest.lx + 1, updest.lx);
  103.              ylocale = rn1(updest.hy - updest.ly + 1, updest.ly);
  104.              break;
  105.          }
  106.          /* find the arrival portal */
  107.          for (t = ftrap; t; t = t->ntrap)
  108.              if (t->ttyp == MAGIC_PORTAL)
  109.                  break;
  110.          if (t) {
  111.              xlocale = t->tx, ylocale = t->ty;
  112.              break;
  113.          } else {
  114.              impossible("mon_arrive: no corresponding portal?");
  115.          } /*FALLTHRU*/
  116.      default:
  117.      case MIGR_RANDOM:
  118.          xlocale = ylocale = 0;
  119.          break;
  120.      }
  121.  
  122.      if (xlocale && wander) {
  123.          /* monster moved a bit; pick a nearby location */
  124.          /* mnearto() deals w/stone, et al */
  125.          char *r = in_rooms(xlocale, ylocale, 0);
  126.          if (r && *r) {
  127.              coord c;
  128.              /* somexy() handles irregular rooms */
  129.              if (somexy(&rooms[*r - ROOMOFFSET], &c))
  130.                  xlocale = c.x, ylocale = c.y;
  131.              else
  132.                  xlocale = ylocale = 0;
  133.          } else { /* not in a room */
  134.              int i, j;
  135.              i = max(1, xlocale - wander);
  136.              j = min(COLNO - 1, xlocale + wander);
  137.              xlocale = rn1(j - i, i);
  138.              i = max(0, ylocale - wander);
  139.              j = min(ROWNO - 1, ylocale + wander);
  140.              ylocale = rn1(j - i, i);
  141.          }
  142.      } /* moved a bit */
  143.  
  144.      mtmp->mx = 0; /*(already is 0)*/
  145.      mtmp->my = xyflags;
  146.      if (xlocale)
  147.          (void) mnearto(mtmp, xlocale, ylocale, FALSE);
  148.      else {
  149.          if (!rloc(mtmp, TRUE)) {
  150.              /*
  151.               * Failed to place migrating monster,
  152.               * probably because the level is full.
  153.               * Dump the monster's cargo and leave the monster dead.
  154.               */
  155.              struct obj *obj;
  156.              while ((obj = mtmp->minvent) != 0) {
  157.                  obj_extract_self(obj);
  158.                  obj_no_longer_held(obj);
  159.                  if (obj->owornmask & W_WEP)
  160.                      setmnotwielded(mtmp, obj);
  161.                  obj->owornmask = 0L;
  162.                  if (xlocale && ylocale)
  163.                      place_object(obj, xlocale, ylocale);
  164.                  else if (rloco(obj)) {
  165.                      if (!get_obj_location(obj, &xlocale, &ylocale, 0))
  166.                          impossible("Can't find relocated object.");
  167.                  }
  168.              }
  169.              (void) mkcorpstat(CORPSE, (struct monst *) 0, mtmp->data, xlocale,
  170.                                ylocale, CORPSTAT_NONE);
  171.              mongone(mtmp);
  172.          }
  173.      }
  174.  }
  175.  

mon_catchup_elapsed_time

  1.  /* heal monster for time spent elsewhere */
  2.  void
  3.  mon_catchup_elapsed_time(mtmp, nmv)
  4.  struct monst *mtmp;
  5.  long nmv; /* number of moves */
  6.  {
  7.      int imv = 0; /* avoid zillions of casts and lint warnings */
  8.  
  9.  #if defined(DEBUG) || defined(BETA)
  10.      if (nmv < 0L) { /* crash likely... */
  11.          panic("catchup from future time?");
  12.          /*NOTREACHED*/
  13.          return;
  14.      } else if (nmv == 0L) { /* safe, but should'nt happen */
  15.          impossible("catchup from now?");
  16.      } else
  17.  #endif
  18.          if (nmv >= LARGEST_INT) /* paranoia */
  19.          imv = LARGEST_INT - 1;
  20.      else
  21.          imv = (int) nmv;
  22.  
  23.      /* might stop being afraid, blind or frozen */
  24.      /* set to 1 and allow final decrement in movemon() */
  25.      if (mtmp->mblinded) {
  26.          if (imv >= (int) mtmp->mblinded)
  27.              mtmp->mblinded = 1;
  28.          else
  29.              mtmp->mblinded -= imv;
  30.      }
  31.      if (mtmp->mfrozen) {
  32.          if (imv >= (int) mtmp->mfrozen)
  33.              mtmp->mfrozen = 1;
  34.          else
  35.              mtmp->mfrozen -= imv;
  36.      }
  37.      if (mtmp->mfleetim) {
  38.          if (imv >= (int) mtmp->mfleetim)
  39.              mtmp->mfleetim = 1;
  40.          else
  41.              mtmp->mfleetim -= imv;
  42.      }
  43.  
  44.      /* might recover from temporary trouble */
  45.      if (mtmp->mtrapped && rn2(imv + 1) > 40 / 2)
  46.          mtmp->mtrapped = 0;
  47.      if (mtmp->mconf && rn2(imv + 1) > 50 / 2)
  48.          mtmp->mconf = 0;
  49.      if (mtmp->mstun && rn2(imv + 1) > 10 / 2)
  50.          mtmp->mstun = 0;
  51.  
  52.      /* might finish eating or be able to use special ability again */
  53.      if (imv > mtmp->meating)
  54.          finish_meating(mtmp);
  55.      else
  56.          mtmp->meating -= imv;
  57.      if (imv > mtmp->mspec_used)
  58.          mtmp->mspec_used = 0;
  59.      else
  60.          mtmp->mspec_used -= imv;
  61.  
  62.      /* reduce tameness for every 150 moves you are separated */
  63.      if (mtmp->mtame) {
  64.          int wilder = (imv + 75) / 150;
  65.          if (mtmp->mtame > wilder)
  66.              mtmp->mtame -= wilder; /* less tame */
  67.          else if (mtmp->mtame > rn2(wilder))
  68.              mtmp->mtame = 0; /* untame */
  69.          else
  70.              mtmp->mtame = mtmp->mpeaceful = 0; /* hostile! */
  71.      }
  72.      /* check to see if it would have died as a pet; if so, go wild instead
  73.       * of dying the next time we call dog_move()
  74.       */
  75.      if (mtmp->mtame && !mtmp->isminion
  76.          && (carnivorous(mtmp->data) || herbivorous(mtmp->data))) {
  77.          struct edog *edog = EDOG(mtmp);
  78.  
  79.          if ((monstermoves > edog->hungrytime + 500 && mtmp->mhp < 3)
  80.              || (monstermoves > edog->hungrytime + 750))
  81.              mtmp->mtame = mtmp->mpeaceful = 0;
  82.      }
  83.  
  84.      if (!mtmp->mtame && mtmp->mleashed) {
  85.          /* leashed monsters should always be with hero, consequently
  86.             never losing any time to be accounted for later */
  87.          impossible("catching up for leashed monster?");
  88.          m_unleash(mtmp, FALSE);
  89.      }
  90.  
  91.      /* recover lost hit points */
  92.      if (!regenerates(mtmp->data))
  93.          imv /= 20;
  94.      if (mtmp->mhp + imv >= mtmp->mhpmax)
  95.          mtmp->mhp = mtmp->mhpmax;
  96.      else
  97.          mtmp->mhp += imv;
  98.  }
  99.  

keepdogs

  1.  /* called when you move to another level */
  2.  void
  3.  keepdogs(pets_only)
  4.  boolean pets_only; /* true for ascension or final escape */
  5.  {
  6.      register struct monst *mtmp, *mtmp2;
  7.      register struct obj *obj;
  8.      int num_segs;
  9.      boolean stay_behind;
  10.  
  11.      for (mtmp = fmon; mtmp; mtmp = mtmp2) {
  12.          mtmp2 = mtmp->nmon;
  13.          if (DEADMONSTER(mtmp))
  14.              continue;
  15.          if (pets_only) {
  16.              if (!mtmp->mtame)
  17.                  continue; /* reject non-pets */
  18.              /* don't block pets from accompanying hero's dungeon
  19.                 escape or ascension simply due to mundane trifles;
  20.                 unlike level change for steed, don't bother trying
  21.                 to achieve a normal trap escape first */
  22.              mtmp->mtrapped = 0;
  23.              mtmp->meating = 0;
  24.              mtmp->msleeping = 0;
  25.              mtmp->mfrozen = 0;
  26.              mtmp->mcanmove = 1;
  27.          }
  28.          if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp))
  29.               /* the wiz will level t-port from anywhere to chase
  30.                  the amulet; if you don't have it, will chase you
  31.                  only if in range. -3. */
  32.               || (u.uhave.amulet && mtmp->iswiz))
  33.              && ((!mtmp->msleeping && mtmp->mcanmove)
  34.                  /* eg if level teleport or new trap, steed has no control
  35.                     to avoid following */
  36.                  || (mtmp == u.usteed))
  37.              /* monster won't follow if it hasn't noticed you yet */
  38.              && !(mtmp->mstrategy & STRAT_WAITFORU)) {
  39.              stay_behind = FALSE;
  40.              if (mtmp->mtrapped)
  41.                  (void) mintrap(mtmp); /* try to escape */
  42.              if (mtmp == u.usteed) {
  43.                  /* make sure steed is eligible to accompany hero */
  44.                  mtmp->mtrapped = 0;       /* escape trap */
  45.                  mtmp->meating = 0;        /* terminate eating */
  46.                  mdrop_special_objs(mtmp); /* drop Amulet */
  47.              } else if (mtmp->meating || mtmp->mtrapped) {
  48.                  if (canseemon(mtmp))
  49.                      pline("%s is still %s.", Monnam(mtmp),
  50.                            mtmp->meating ? "eating" : "trapped");
  51.                  stay_behind = TRUE;
  52.              } else if (mon_has_amulet(mtmp)) {
  53.                  if (canseemon(mtmp))
  54.                      pline("%s seems very disoriented for a moment.",
  55.                            Monnam(mtmp));
  56.                  stay_behind = TRUE;
  57.              }
  58.              if (stay_behind) {
  59.                  if (mtmp->mleashed) {
  60.                      pline("%s leash suddenly comes loose.",
  61.                            humanoid(mtmp->data)
  62.                                ? (mtmp->female ? "Her" : "His")
  63.                                : "Its");
  64.                      m_unleash(mtmp, FALSE);
  65.                  }
  66.                  if (mtmp == u.usteed) {
  67.                      /* can't happen unless someone makes a change
  68.                         which scrambles the stay_behind logic above */
  69.                      impossible("steed left behind?");
  70.                      dismount_steed(DISMOUNT_GENERIC);
  71.                  }
  72.                  continue;
  73.              }
  74.              if (mtmp->isshk)
  75.                  set_residency(mtmp, TRUE);
  76.  
  77.              if (mtmp->wormno) {
  78.                  register int cnt;
  79.                  /* NOTE: worm is truncated to # segs = max wormno size */
  80.                  cnt = count_wsegs(mtmp);
  81.                  num_segs = min(cnt, MAX_NUM_WORMS - 1);
  82.                  wormgone(mtmp);
  83.              } else
  84.                  num_segs = 0;
  85.  
  86.              /* set minvent's obj->no_charge to 0 */
  87.              for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  88.                  if (Has_contents(obj))
  89.                      picked_container(obj); /* does the right thing */
  90.                  obj->no_charge = 0;
  91.              }
  92.  
  93.              relmon(mtmp, &mydogs);   /* move it from map to mydogs */
  94.              mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */
  95.              mtmp->wormno = num_segs;
  96.              mtmp->mlstmv = monstermoves;
  97.          } else if (mtmp->iswiz) {
  98.              /* we want to be able to find him when his next resurrection
  99.                 chance comes up, but have him resume his present location
  100.                 if player returns to this level before that time */
  101.              migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_EXACT_XY,
  102.                               (coord *) 0);
  103.          } else if (mtmp->mleashed) {
  104.              /* this can happen if your quest leader ejects you from the
  105.                 "home" level while a leashed pet isn't next to you */
  106.              pline("%s leash goes slack.", s_suffix(Monnam(mtmp)));
  107.              m_unleash(mtmp, FALSE);
  108.          }
  109.      }
  110.  }
  111.  

migrate_to_level

  1.  void
  2.  migrate_to_level(mtmp, tolev, xyloc, cc)
  3.  register struct monst *mtmp;
  4.  xchar tolev; /* destination level */
  5.  xchar xyloc; /* MIGR_xxx destination xy location: */
  6.  coord *cc;   /* optional destination coordinates */
  7.  {
  8.      register struct obj *obj;
  9.      d_level new_lev;
  10.      xchar xyflags;
  11.      int num_segs = 0; /* count of worm segments */
  12.  
  13.      if (mtmp->isshk)
  14.          set_residency(mtmp, TRUE);
  15.  
  16.      if (mtmp->wormno) {
  17.          register int cnt;
  18.          /* **** NOTE: worm is truncated to # segs = max wormno size **** */
  19.          cnt = count_wsegs(mtmp);
  20.          num_segs = min(cnt, MAX_NUM_WORMS - 1);
  21.          wormgone(mtmp);
  22.      }
  23.  
  24.      /* set minvent's obj->no_charge to 0 */
  25.      for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  26.          if (Has_contents(obj))
  27.              picked_container(obj); /* does the right thing */
  28.          obj->no_charge = 0;
  29.      }
  30.  
  31.      if (mtmp->mleashed) {
  32.          mtmp->mtame--;
  33.          m_unleash(mtmp, TRUE);
  34.      }
  35.      relmon(mtmp, &migrating_mons); /* move it from map to migrating_mons */
  36.  
  37.      new_lev.dnum = ledger_to_dnum((xchar) tolev);
  38.      new_lev.dlevel = ledger_to_dlev((xchar) tolev);
  39.      /* overload mtmp->[mx,my], mtmp->[mux,muy], and mtmp->mtrack[] as */
  40.      /* destination codes (setup flag bits before altering mx or my) */
  41.      xyflags = (depth(&new_lev) < depth(&u.uz)); /* 1 => up */
  42.      if (In_W_tower(mtmp->mx, mtmp->my, &u.uz))
  43.          xyflags |= 2;
  44.      mtmp->wormno = num_segs;
  45.      mtmp->mlstmv = monstermoves;
  46.      mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx;
  47.      mtmp->mtrack[1].y = cc ? cc->y : mtmp->my;
  48.      mtmp->mtrack[0].x = xyloc;
  49.      mtmp->mtrack[0].y = xyflags;
  50.      mtmp->mux = new_lev.dnum;
  51.      mtmp->muy = new_lev.dlevel;
  52.      mtmp->mx = mtmp->my = 0; /* this implies migration */
  53.      if (mtmp == context.polearm.hitmon)
  54.          context.polearm.hitmon = NULL;
  55.  }
  56.  

dogfood

  1.  /* return quality of food; the lower the better */
  2.  /* fungi will eat even tainted food */
  3.  int
  4.  dogfood(mon, obj)
  5.  struct monst *mon;
  6.  register struct obj *obj;
  7.  {
  8.      struct permonst *mptr = mon->data, *fptr = 0;
  9.      boolean carni = carnivorous(mptr), herbi = herbivorous(mptr), starving;
  10.  
  11.      if (is_quest_artifact(obj) || obj_resists(obj, 0, 95))
  12.          return obj->cursed ? TABU : APPORT;
  13.  
  14.      switch (obj->oclass) {
  15.      case FOOD_CLASS:
  16.          if (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG)
  17.              fptr = &mons[obj->corpsenm];
  18.  
  19.          if (obj->otyp == CORPSE && is_rider(fptr))
  20.              return TABU;
  21.          if ((obj->otyp == CORPSE || obj->otyp == EGG) && touch_petrifies(fptr)
  22.              && !resists_ston(mon))
  23.              return POISON;
  24.          if (!carni && !herbi)
  25.              return obj->cursed ? UNDEF : APPORT;
  26.  
  27.          /* a starving pet will eat almost anything */
  28.          starving =
  29.              (mon->mtame && !mon->isminion && EDOG(mon)->mhpmax_penalty);
  30.  
  31.          /* ghouls prefer old corpses and unhatchable eggs, yum!
  32.             they'll eat fresh non-veggy corpses and hatchable eggs
  33.             when starving; they never eat stone-to-flesh'd meat */
  34.          if (mptr == &mons[PM_GHOUL]) {
  35.              if (obj->otyp == CORPSE)
  36.                  return (peek_at_iced_corpse_age(obj) + 50L <= monstermoves
  37.                          && fptr != &mons[PM_LIZARD]
  38.                          && fptr != &mons[PM_LICHEN])
  39.                             ? DOGFOOD
  40.                             : (starving && !vegan(fptr))
  41.                                ? ACCFOOD
  42.                                : POISON;
  43.              if (obj->otyp == EGG)
  44.                  return stale_egg(obj) ? CADAVER : starving ? ACCFOOD : POISON;
  45.              return TABU;
  46.          }
  47.  
  48.          switch (obj->otyp) {
  49.          case TRIPE_RATION:
  50.          case MEATBALL:
  51.          case MEAT_RING:
  52.          case MEAT_STICK:
  53.          case HUGE_CHUNK_OF_MEAT:
  54.              return carni ? DOGFOOD : MANFOOD;
  55.          case EGG:
  56.              return carni ? CADAVER : MANFOOD;
  57.          case CORPSE:
  58.              if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves
  59.                   && obj->corpsenm != PM_LIZARD && obj->corpsenm != PM_LICHEN
  60.                   && mptr->mlet != S_FUNGUS)
  61.                  || (acidic(fptr) && !resists_acid(mon))
  62.                  || (poisonous(fptr) && !resists_poison(mon)))
  63.                  return POISON;
  64.              /* turning into slime is preferable to starvation */
  65.              else if (fptr == &mons[PM_GREEN_SLIME] && !slimeproof(mon->data))
  66.                  return starving ? ACCFOOD : POISON;
  67.              else if (vegan(fptr))
  68.                  return herbi ? CADAVER : MANFOOD;
  69.              /* most humanoids will avoid cannibalism unless starving;
  70.                 arbitrary: elves won't eat other elves even then */
  71.              else if (humanoid(mptr) && same_race(mptr, fptr)
  72.                       && (!is_undead(mptr) && fptr->mlet != S_KOBOLD
  73.                           && fptr->mlet != S_ORC && fptr->mlet != S_OGRE))
  74.                  return (starving && carni && !is_elf(mptr)) ? ACCFOOD : TABU;
  75.              else
  76.                  return carni ? CADAVER : MANFOOD;
  77.          case CLOVE_OF_GARLIC:
  78.              return (is_undead(mptr) || is_vampshifter(mon))
  79.                        ? TABU
  80.                        : (herbi || starving)
  81.                           ? ACCFOOD
  82.                           : MANFOOD;
  83.          case TIN:
  84.              return metallivorous(mptr) ? ACCFOOD : MANFOOD;
  85.          case APPLE:
  86.          case CARROT:
  87.              return herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD;
  88.          case BANANA:
  89.              return (mptr->mlet == S_YETI)
  90.                        ? DOGFOOD
  91.                        : (herbi || starving)
  92.                           ? ACCFOOD
  93.                           : MANFOOD;
  94.          default:
  95.              if (starving)
  96.                  return ACCFOOD;
  97.              return (obj->otyp > SLIME_MOLD) ? (carni ? ACCFOOD : MANFOOD)
  98.                                              : (herbi ? ACCFOOD : MANFOOD);
  99.          }
  100.      default:
  101.          if (obj->otyp == AMULET_OF_STRANGULATION
  102.              || obj->otyp == RIN_SLOW_DIGESTION)
  103.              return TABU;
  104.          if (mon_hates_silver(mon) && objects[obj->otyp].oc_material == SILVER)
  105.              return TABU;
  106.          if (mptr == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
  107.              return ACCFOOD;
  108.          if (metallivorous(mptr) && is_metallic(obj)
  109.              && (is_rustprone(obj) || mptr != &mons[PM_RUST_MONSTER])) {
  110.              /* Non-rustproofed ferrous based metals are preferred. */
  111.              return (is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD
  112.                                                              : ACCFOOD;
  113.          }
  114.          if (!obj->cursed
  115.              && obj->oclass != BALL_CLASS
  116.              && obj->oclass != CHAIN_CLASS)
  117.              return APPORT;
  118.          /*FALLTHRU*/
  119.      case ROCK_CLASS:
  120.          return UNDEF;
  121.      }
  122.  }
  123.  

tamedog

  1.  /*
  2.   * With the separate mextra structure added in 3.6.x this always
  3.   * operates on the original mtmp. It now returns TRUE if the taming
  4.   * succeeded.
  5.   */
  6.  boolean
  7.  tamedog(mtmp, obj)
  8.  register struct monst *mtmp;
  9.  register struct obj *obj;
  10.  {
  11.      /* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */
  12.      if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA]
  13.          || (mtmp->data->mflags3 & M3_WANTSARTI))
  14.          return FALSE;
  15.  
  16.      /* worst case, at least it'll be peaceful. */
  17.      mtmp->mpeaceful = 1;
  18.      set_malign(mtmp);
  19.      if (flags.moonphase == FULL_MOON && night() && rn2(6) && obj
  20.          && mtmp->data->mlet == S_DOG)
  21.          return FALSE;
  22.  
  23.      /* If we cannot tame it, at least it's no longer afraid. */
  24.      mtmp->mflee = 0;
  25.      mtmp->mfleetim = 0;
  26.  
  27.      /* make grabber let go now, whether it becomes tame or not */
  28.      if (mtmp == u.ustuck) {
  29.          if (u.uswallow)
  30.              expels(mtmp, mtmp->data, TRUE);
  31.          else if (!(Upolyd && sticks(youmonst.data)))
  32.              unstuck(mtmp);
  33.      }
  34.  
  35.      /* feeding it treats makes it tamer */
  36.      if (mtmp->mtame && obj) {
  37.          int tasty;
  38.  
  39.          if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating
  40.              && ((tasty = dogfood(mtmp, obj)) == DOGFOOD
  41.                  || (tasty <= ACCFOOD
  42.                      && EDOG(mtmp)->hungrytime <= monstermoves))) {
  43.              /* pet will "catch" and eat this thrown food */
  44.              if (canseemon(mtmp)) {
  45.                  boolean big_corpse =
  46.                      (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM
  47.                       && mons[obj->corpsenm].msize > mtmp->data->msize);
  48.                  pline("%s catches %s%s", Monnam(mtmp), the(xname(obj)),
  49.                        !big_corpse ? "." : ", or vice versa!");
  50.              } else if (cansee(mtmp->mx, mtmp->my))
  51.                  pline("%s.", Tobjnam(obj, "stop"));
  52.              /* dog_eat expects a floor object */
  53.              place_object(obj, mtmp->mx, mtmp->my);
  54.              (void) dog_eat(mtmp, obj, mtmp->mx, mtmp->my, FALSE);
  55.              /* eating might have killed it, but that doesn't matter here;
  56.                 a non-null result suppresses "miss" message for thrown
  57.                 food and also implies that the object has been deleted */
  58.              return TRUE;
  59.          } else
  60.              return FALSE;
  61.      }
  62.  
  63.      if (mtmp->mtame || !mtmp->mcanmove
  64.          /* monsters with conflicting structures cannot be tamed */
  65.          || mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion
  66.          || is_covetous(mtmp->data) || is_human(mtmp->data)
  67.          || (is_demon(mtmp->data) && !is_demon(youmonst.data))
  68.          || (obj && dogfood(mtmp, obj) >= MANFOOD))
  69.          return FALSE;
  70.  
  71.      if (mtmp->m_id == quest_status.leader_m_id)
  72.          return FALSE;
  73.  
  74.      /* add the pet extension */
  75.      newedog(mtmp);
  76.      initedog(mtmp);
  77.  
  78.      if (obj) { /* thrown food */
  79.          /* defer eating until the edog extension has been set up */
  80.          place_object(obj, mtmp->mx, mtmp->my); /* put on floor */
  81.          /* devour the food (might grow into larger, genocided monster) */
  82.          if (dog_eat(mtmp, obj, mtmp->mx, mtmp->my, TRUE) == 2)
  83.              return TRUE; /* oops, it died... */
  84.          /* `obj' is now obsolete */
  85.      }
  86.  
  87.      newsym(mtmp->mx, mtmp->my);
  88.      if (attacktype(mtmp->data, AT_WEAP)) {
  89.          mtmp->weapon_check = NEED_HTH_WEAPON;
  90.          (void) mon_wield_item(mtmp);
  91.      }
  92.      return TRUE;
  93.  }
  94.  

wary_dog

  1.  /*
  2.   * Called during pet revival or pet life-saving.
  3.   * If you killed the pet, it revives wild.
  4.   * If you abused the pet a lot while alive, it revives wild.
  5.   * If you abused the pet at all while alive, it revives untame.
  6.   * If the pet wasn't abused and was very tame, it might revive tame.
  7.   */
  8.  void
  9.  wary_dog(mtmp, was_dead)
  10.  struct monst *mtmp;
  11.  boolean was_dead;
  12.  {
  13.      struct edog *edog;
  14.      boolean quietly = was_dead;
  15.  
  16.      finish_meating(mtmp);
  17.  
  18.      if (!mtmp->mtame)
  19.          return;
  20.      edog = !mtmp->isminion ? EDOG(mtmp) : 0;
  21.  
  22.      /* if monster was starving when it died, undo that now */
  23.      if (edog && edog->mhpmax_penalty) {
  24.          mtmp->mhpmax += edog->mhpmax_penalty;
  25.          mtmp->mhp += edog->mhpmax_penalty; /* heal it */
  26.          edog->mhpmax_penalty = 0;
  27.      }
  28.  
  29.      if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) {
  30.          mtmp->mpeaceful = mtmp->mtame = 0;
  31.          if (edog->abuse >= 0 && edog->abuse < 10)
  32.              if (!rn2(edog->abuse + 1))
  33.                  mtmp->mpeaceful = 1;
  34.          if (!quietly && cansee(mtmp->mx, mtmp->my)) {
  35.              if (haseyes(youmonst.data)) {
  36.                  if (haseyes(mtmp->data))
  37.                      pline("%s %s to look you in the %s.", Monnam(mtmp),
  38.                            mtmp->mpeaceful ? "seems unable" : "refuses",
  39.                            body_part(EYE));
  40.                  else
  41.                      pline("%s avoids your gaze.", Monnam(mtmp));
  42.              }
  43.          }
  44.      } else {
  45.          /* chance it goes wild anyway - Pet Sematary */
  46.          mtmp->mtame = rn2(mtmp->mtame + 1);
  47.          if (!mtmp->mtame)
  48.              mtmp->mpeaceful = rn2(2);
  49.      }
  50.  
  51.      if (!mtmp->mtame) {
  52.          if (!quietly && canspotmon(mtmp))
  53.              pline("%s %s.", Monnam(mtmp),
  54.                    mtmp->mpeaceful ? "is no longer tame" : "has become feral");
  55.          newsym(mtmp->mx, mtmp->my);
  56.          /* a life-saved monster might be leashed;
  57.             don't leave it that way if it's no longer tame */
  58.          if (mtmp->mleashed)
  59.              m_unleash(mtmp, TRUE);
  60.          if (mtmp == u.usteed)
  61.              dismount_steed(DISMOUNT_THROWN);
  62.      } else if (edog) {
  63.          /* it's still a pet; start a clean pet-slate now */
  64.          edog->revivals++;
  65.          edog->killed_by_u = 0;
  66.          edog->abuse = 0;
  67.          edog->ogoal.x = edog->ogoal.y = -1;
  68.          if (was_dead || edog->hungrytime < monstermoves + 500L)
  69.              edog->hungrytime = monstermoves + 500L;
  70.          if (was_dead) {
  71.              edog->droptime = 0L;
  72.              edog->dropdist = 10000;
  73.              edog->whistletime = 0L;
  74.              edog->apport = 5;
  75.          } /* else lifesaved, so retain current values */
  76.      }
  77.  }
  78.  

abuse_dog

  1.  void
  2.  abuse_dog(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      if (!mtmp->mtame)
  6.          return;
  7.  
  8.      if (Aggravate_monster || Conflict)
  9.          mtmp->mtame /= 2;
  10.      else
  11.          mtmp->mtame--;
  12.  
  13.      if (mtmp->mtame && !mtmp->isminion)
  14.          EDOG(mtmp)->abuse++;
  15.  
  16.      if (!mtmp->mtame && mtmp->mleashed)
  17.          m_unleash(mtmp, TRUE);
  18.  
  19.      /* don't make a sound if pet is in the middle of leaving the level */
  20.      /* newsym isn't necessary in this case either */
  21.      if (mtmp->mx != 0) {
  22.          if (mtmp->mtame && rn2(mtmp->mtame))
  23.              yelp(mtmp);
  24.          else
  25.              growl(mtmp); /* give them a moment's worry */
  26.  
  27.          if (!mtmp->mtame)
  28.              newsym(mtmp->mx, mtmp->my);
  29.      }
  30.  }
  31.  
  32.  /*dog.c*/