]> granicus.if.org Git - nethack/commitdiff
B01004 No mimic corpse effect on pet (trunk only)
authornethack.allison <nethack.allison>
Wed, 12 Nov 2003 03:28:26 +0000 (03:28 +0000)
committernethack.allison <nethack.allison>
Wed, 12 Nov 2003 03:28:26 +0000 (03:28 +0000)
Make a mimic effect that lasts only as long as the
pet is still consuming the corpse.

include/extern.h
src/dog.c
src/dogmove.c
src/dokick.c
src/mon.c
src/monmove.c
src/pline.c

index 883aa35674f6a74c724f22428977a7677bb6d2c3..4c757a274bafd895f3f7bdeb50b9f3f6f5296c6d 100644 (file)
@@ -422,6 +422,7 @@ E int FDECL(dog_move, (struct monst *,int));
 #ifdef USE_TRAMPOLI
 E void FDECL(wantdoor, (int,int,genericptr_t));
 #endif
+E void FDECL(finish_meating,(struct monst *));
 
 /* ### dokick.c ### */
 
index 2104292f63f53c3492d112dabd9b003e266f9f89..45073ff1e01e87e35f01a0f3e59836d2f3f84baf 100644 (file)
--- a/src/dog.c
+++ b/src/dog.c
@@ -436,7 +436,7 @@ long nmv;           /* number of moves */
        if (mtmp->mstun    && rn2(imv + 1) > 10/2) mtmp->mstun = 0;
 
        /* might finish eating or be able to use special ability again */
-       if (imv > mtmp->meating) mtmp->meating = 0;
+       if (imv > mtmp->meating) finish_meating(mtmp);
        else mtmp->meating -= imv;
        if (imv > mtmp->mspec_used) mtmp->mspec_used = 0;
        else mtmp->mspec_used -= imv;
@@ -837,7 +837,8 @@ boolean was_dead;
     struct edog *edog;
     boolean quietly = was_dead;
 
-    mtmp->meating = 0;
+    finish_meating(mtmp);
+
     if (!mtmp->mtame) return;
     edog = !mtmp->isminion ? EDOG(mtmp) : 0;
 
index 2dd36f3394eb1b9a1c66b2484630acaea610b994..987d31f969f68ee8d65be2a1cf085d19194b094a 100644 (file)
@@ -17,6 +17,7 @@ STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *));
 STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P,
     XCHAR_P,XCHAR_P));
 STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));
+STATIC_DCL void FDECL(quickmimic, (struct monst *));
 
 STATIC_OVL struct obj *
 DROPPABLES(mon)
@@ -124,10 +125,17 @@ boolean devour;
        register struct edog *edog = EDOG(mtmp);
        boolean poly = FALSE, grow = FALSE, heal = FALSE;
        int nutrit;
+       boolean deadmimic = FALSE;
 
        if(edog->hungrytime < monstermoves)
            edog->hungrytime = monstermoves;
        nutrit = dog_nutrition(mtmp, obj);
+
+       deadmimic = (obj->otyp == CORPSE &&
+                    (obj->corpsenm == PM_SMALL_MIMIC ||
+                     obj->corpsenm == PM_LARGE_MIMIC ||
+                     obj->corpsenm == PM_GIANT_MIMIC));
+
        poly = polyfodder(obj);
        grow = mlevelgain(obj);
        heal = mhealup(obj);
@@ -192,11 +200,13 @@ boolean devour;
            (void) newcham(mtmp, (struct permonst *)0, FALSE,
                           cansee(mtmp->mx, mtmp->my));
        }
+
        /* limit "instant" growth to prevent potential abuse */
        if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) {
            if (!grow_up(mtmp, (struct monst *)0)) return 2;
        }
        if (heal) mtmp->mhp = mtmp->mhpmax;
+       if (deadmimic) quickmimic(mtmp);
        return 1;
 }
 
@@ -853,4 +863,79 @@ genericptr_t distance;
     }
 }
 
+
+static struct qmchoices {
+       int mndx;                       /* type of pet, 0 means any  */
+       char mlet;                      /* symbol of pet, 0 means any */
+       unsigned mappearance;           /* mimic this */
+       uchar m_ap_type;                /* what is the thing it is mimicing? */
+} qm[] = {
+       /* Things that some pets might be thinking about at the time */
+       {PM_LITTLE_DOG, 0, PM_KITTEN,     M_AP_MONSTER},
+       {PM_LARGE_DOG,  0, PM_LARGE_CAT,  M_AP_MONSTER},
+       {PM_KITTEN,     0, PM_LITTLE_DOG, M_AP_MONSTER},
+       {PM_LARGE_CAT,  0, PM_LARGE_DOG,  M_AP_MONSTER},
+       {PM_HOUSECAT,   0, PM_DOG,        M_AP_MONSTER},
+       {PM_DOG,        0, PM_HOUSECAT,   M_AP_MONSTER},
+       {PM_HOUSECAT,   0, PM_GIANT_RAT,  M_AP_MONSTER},
+#ifdef SINKS
+       {0, S_DOG, SINK, M_AP_FURNITURE},       /* sorry, no fire hydrants in NetHack */
+#endif
+       {0, 0, TRIPE_RATION, M_AP_OBJECT},      /* leave this at end */
+};
+
+void
+finish_meating(mtmp)
+struct monst *mtmp;
+{
+       mtmp->meating = 0;
+       if (mtmp->m_ap_type && mtmp->mappearance && !mtmp->cham) {
+               /* was eating a mimic and now appearance needs resetting */
+               mtmp->m_ap_type = 0;
+               mtmp->mappearance = 0;
+               newsym(mtmp->mx, mtmp->my);
+       }
+}
+
+STATIC_OVL void
+quickmimic(mtmp)
+struct monst *mtmp;
+{
+       int idx = 0, trycnt = 5;
+       char buf[BUFSZ];
+
+       if (Protection_from_shape_changers || Blind || !mtmp->meating) return;
+
+       do {
+               idx = rn2(SIZE(qm));
+               if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
+                       break;
+               if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
+                       break;
+               if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
+                       break;
+       } while (--trycnt > 0);
+       if (trycnt == 0) idx = SIZE(qm)-1;
+       if (!idx) return;       /* impossible */
+
+       Strcpy(buf, mon_nam(mtmp));
+
+       mtmp->m_ap_type = qm[idx].m_ap_type;
+       mtmp->mappearance = qm[idx].mappearance;
+
+       newsym(mtmp->mx,mtmp->my);
+       You("see %s appear where %s was!",
+               (mtmp->m_ap_type == M_AP_FURNITURE) ?
+                       an(defsyms[mtmp->mappearance].explanation) :
+               (mtmp->m_ap_type == M_AP_OBJECT &&
+                               OBJ_DESCR(objects[mtmp->mappearance])) ?
+                       an(OBJ_DESCR(objects[mtmp->mappearance])) :
+               (mtmp->m_ap_type == M_AP_OBJECT &&
+                               OBJ_NAME(objects[mtmp->mappearance])) ?
+                       an(OBJ_NAME(objects[mtmp->mappearance])) :
+               (mtmp->m_ap_type == M_AP_MONSTER) ?
+                       an(mons[mtmp->mappearance].mname) : something, buf);
+       display_nhwindow(WIN_MAP, TRUE);
+}
+
 /*dogmove.c*/
index 07d0ebbb3ac35b1f8382ceff7373cbb4fb67006a..43169418df5797a2a26aa042fa303da2f3fc700b 100644 (file)
@@ -250,7 +250,7 @@ register struct obj *gold;
                 long value = gold->quan * objects[gold->otyp].oc_cost;
 #endif
                mtmp->msleeping = 0;
-               mtmp->meating = 0;
+               finish_meating(mtmp);
                if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
 
                /* greedy monsters catch gold */
index f5d73d97a80a65fe2e3b11094322694ce0223c69..ffa2c66d860aa4c71572da83fe0223ba9aeb4631 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -2098,7 +2098,7 @@ wakeup(mtmp)
 register struct monst *mtmp;
 {
        mtmp->msleeping = 0;
-       mtmp->meating = 0;      /* assume there's no salvagable food left */
+       finish_meating(mtmp);
        setmangry(mtmp);
        if(mtmp->m_ap_type) seemimic(mtmp);
        else if (context.forcefight && !context.mon_moving && mtmp->mundetected) {
index 37dddf3362e0c374ba44cb107f0f03a8012e4cd2..9f2696a5d277b976d6139c8bca14cee1c84004df 100644 (file)
@@ -141,7 +141,10 @@ boolean digest_meal;
            (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++;
        if (mon->mspec_used) mon->mspec_used--;
        if (digest_meal) {
-           if (mon->meating) mon->meating--;
+           if (mon->meating) {
+               mon->meating--;
+               if (mon->meating <= 0) finish_meating(mon);
+           }
        }
 }
 
@@ -603,6 +606,7 @@ register int after;
 
        if (mtmp->meating) {
            mtmp->meating--;
+           if (mtmp->meating <= 0) finish_meating(mtmp);
            return 3;                   /* still eating */
        }
        if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10))
index ea863dd7ef10e1b8124c136c088321e10baee779..2febc95f058ddf3b7852e00b624786f0717179ed 100644 (file)
@@ -305,6 +305,21 @@ register struct monst *mtmp;
        }
        else if (mtmp->mpeaceful) Strcat(info, ", peaceful");
        if (mtmp->meating)        Strcat(info, ", eating");
+       if (mtmp->meating && !mtmp->cham &&
+           mtmp->mappearance && mtmp->m_ap_type) {
+               Sprintf(eos(info), ", mimicing %s",
+                   (mtmp->m_ap_type == M_AP_FURNITURE) ?
+                       an(defsyms[mtmp->mappearance].explanation) :
+                   (mtmp->m_ap_type == M_AP_OBJECT &&
+                               OBJ_DESCR(objects[mtmp->mappearance])) ?
+                       an(OBJ_DESCR(objects[mtmp->mappearance])) :
+                   (mtmp->m_ap_type == M_AP_OBJECT &&
+                               OBJ_NAME(objects[mtmp->mappearance])) ?
+                       an(OBJ_NAME(objects[mtmp->mappearance])) :
+                   (mtmp->m_ap_type == M_AP_MONSTER) ?
+                       an(mons[mtmp->mappearance].mname) :
+                       something);
+       }
        if (mtmp->mcan)           Strcat(info, ", cancelled");
        if (mtmp->mconf)          Strcat(info, ", confused");
        if (mtmp->mblinded || !mtmp->mcansee)