]> granicus.if.org Git - nethack/commitdiff
buglist: cutting Shopkeeper the long worm
authorcohrs <cohrs>
Thu, 23 Oct 2003 02:30:46 +0000 (02:30 +0000)
committercohrs <cohrs>
Thu, 23 Oct 2003 02:30:46 +0000 (02:30 +0000)
Cutting a shopkeeper poly'd as a long worm would generate strange messages
and could result in a crash.  cutworm didn't deal with all the intricacies
of duplicating a monster.   Fixed by changing cutworm() to use clone_mon()
to do most of its dirty work.  It seems to me that without this change,
cutting a tame long worm could also have similar bad effects.
Other side effects of this change:
- clone_mon now takes x,y coordinates, 0,0 results in previous behavior
- clone_mon no longer always makes cloned monsters tame/peaceful if player
  caused the clone, using the same formula previously in cutworm.  Someone
  else may wish to tweak this for gremlins.
- clone_mon will christen the new mon with the old shopkeeper's name, even
  though clones are never shopkeepers (game can't handle 2 for a shop)
- cutworm can now be called during conflict or pet combat, although I
  added no such calls (yet)

doc/fixes34.3
include/extern.h
src/makemon.c
src/mhitm.c
src/potion.c
src/uhitm.c
src/worm.c

index ba2a7c765f5f08950bc0a933f760bc16e444fbd0..75aee399859b7d46f66f891afffd8ffe614bde4a 100644 (file)
@@ -66,6 +66,8 @@ avoid traveling into water/lava, using usual running rules
 unchanging iron golem would still rehumanize in a rust trap
 fix an impossible rndmonst: bad `mndx' bug
 pets should not try to go after objects that they can't reach
+cutting a shopkeeper polymorphed in to a long worm would generate strange
+       messages and could cause a crash
 
 
 Platform- and/or Interface-Specific Fixes
index 89c4e6d5697dc4f8a071f40c19061ec56efa098e..8a024a3db853d266cfc787acab3acc00602108c4 100644 (file)
@@ -926,7 +926,7 @@ E void FDECL(readmail, (struct obj *));
 /* ### makemon.c ### */
 
 E boolean FDECL(is_home_elemental, (struct permonst *));
-E struct monst *FDECL(clone_mon, (struct monst *));
+E struct monst *FDECL(clone_mon, (struct monst *,XCHAR_P,XCHAR_P));
 E struct monst *FDECL(makemon, (struct permonst *,int,int,int));
 E boolean FDECL(create_critters, (int,struct permonst *));
 E struct permonst *NDECL(rndmonst);
index a6cd84f4207b61bdb2a5668105640a2ce255bdb5..f4337b48af006ef5a5d2be918091847138e66d0c 100644 (file)
@@ -655,9 +655,11 @@ register struct    monst   *mtmp;
 #endif
 }
 
+/* Note: for long worms, always call cutworm (cutworm calls clone_mon) */
 struct monst *
-clone_mon(mon)
+clone_mon(mon, x, y)
 struct monst *mon;
+xchar x, y;    /* clone's preferred location or 0 (near mon) */
 {
        coord mm;
        struct monst *m2;
@@ -666,10 +668,21 @@ struct monst *mon;
        if (mon->mhp <= 1 || (mvitals[monsndx(mon->data)].mvflags & G_EXTINCT))
            return (struct monst *)0;
 
-       mm.x = mon->mx;
-       mm.y = mon->my;
-       if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
-           return (struct monst *)0;
+       if (x == 0) {
+           mm.x = mon->mx;
+           mm.y = mon->my;
+           if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
+               return (struct monst *)0;
+       } else if (!isok(x, y)) {
+           return (struct monst *)0;   /* paranoia */
+       } else {
+           mm.x = x;
+           mm.y = y;
+           if (MON_AT(mm.x, mm.y)) {
+               if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
+                   return (struct monst *)0;
+           }
+       }
        m2 = newmonst(0);
        *m2 = *mon;                     /* copy condition of old monster */
        m2->nmon = fmon;
@@ -708,9 +721,20 @@ struct monst *mon;
        if (m2->mnamelth) {
            m2->mnamelth = 0; /* or it won't get allocated */
            m2 = christen_monst(m2, NAME(mon));
+       } else if (mon->isshk) {
+           m2 = christen_monst(m2, shkname(mon));
        }
+
+       /* not all clones caused by player are tame or peaceful */
+       if (!context.mon_moving) {
+           if (mon->mtame)
+               m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0;
+           else if (mon->mpeaceful)
+               m2->mpeaceful = rn2(max(2 + u.uluck, 2)) ? 1 : 0;
+       }
+
        newsym(m2->mx,m2->my);  /* display the new monster */
-       if (mon->mtame) {
+       if (m2->mtame) {
            struct monst *m3;
 
            if (mon->isminion) {
@@ -733,6 +757,8 @@ struct monst *mon;
                }
            }
        }
+       set_malign(m2);
+
        return m2;
 }
 
index 717dec170129a3f8f615083924e58179b36d3fbe..3e2a3592ad70188dba7c0a7b2b796f33f62ec59b 100644 (file)
@@ -280,7 +280,7 @@ mattackm(magr, mdef)
                       && otmp && objects[otmp->otyp].oc_material == IRON
                       && mdef->mhp > 1 && !mdef->mcan)
                    {
-                       if (clone_mon(mdef)) {
+                       if (clone_mon(mdef, 0, 0)) {
                            if (vis) {
                                char buf[BUFSZ];
 
index 5c1dff265e9f530e377684c023e05465f9363464..788293a63f41206ef0959a9fdb725f476a7179a0 100644 (file)
@@ -2008,7 +2008,7 @@ struct monst *mon,        /* monster being split */
                You("multiply%s!", reason);
            }
        } else {
-           mtmp2 = clone_mon(mon);
+           mtmp2 = clone_mon(mon, 0, 0);
            if (mtmp2) {
                mtmp2->mhpmax = mon->mhpmax / 2;
                mon->mhpmax -= mtmp2->mhpmax;
index 6f115ba856550691280983a28cd12e9446fb79be..ebe8cebd52bca7ce1acbb3a962587b183eb287b6 100644 (file)
@@ -1007,7 +1007,7 @@ int thrown;
                   && objects[obj->otyp].oc_material == IRON
                   && mon->mhp > 1 && !thrown && !mon->mcan
                   /* && !destroyed  -- guaranteed by mhp > 1 */ ) {
-               if (clone_mon(mon)) {
+               if (clone_mon(mon, 0, 0)) {
                        pline("%s divides as you hit it!", Monnam(mon));
                        hittxt = TRUE;
                }
index 3d7a32763a42bdd8cf21719b7afaf88e838523c3..a965f948c364363d4aa63f5e9988b64f7f18633f 100644 (file)
@@ -341,7 +341,7 @@ cutworm(worm, x, y, weap)
     while ( (curr->wx != x) || (curr->wy != y) ) {
        curr = curr->nseg;
        if (!curr) {
-           impossible("cut_worm:  no segment at (%d,%d)", (int) x, (int) y);
+           impossible("cutworm: no segment at (%d,%d)", (int) x, (int) y);
            return;
        }
     }
@@ -368,27 +368,19 @@ cutworm(worm, x, y, weap)
 
     /* Sometimes the tail end dies. */
     if (rn2(3) || !(new_wnum = get_wormno())) {
-       You("cut part of the tail off of %s.", mon_nam(worm));
+       if (context.mon_moving)
+           pline("Part of the tail of %s is cut off.", mon_nam(worm));
+       else
+           You("cut part of the tail off of %s.", mon_nam(worm));
        toss_wsegs(new_tail, TRUE);
        if (worm->mhp > 1) worm->mhp /= 2;
        return;
     }
 
-    /* Create the second worm. */
-    new_worm  = newmonst(0);
-    *new_worm = *worm;                 /* make a copy of the old worm */
-    new_worm->m_id = context.ident++;  /* make sure it has a unique id */
+    remove_monster(x, y);              /* clone_mon puts new head here */
+    new_worm = clone_mon(worm, x, y);
     new_worm->wormno = new_wnum;       /* affix new worm number */
 
-    if (worm->mtame)
-       new_worm->mtame = (rn2(max(2 + u.uluck, 2)) ? worm->mtame : 0);
-    else
-       if (worm->mpeaceful)
-           new_worm->mpeaceful = (rn2(max(2 + u.uluck, 2)) ? 1 : 0);
-    set_malign(new_worm);
-
-    new_worm->mxlth = new_worm->mnamelth = 0;
-
     /* Devalue the monster level of both halves of the worm. */
     worm->m_lev = ((unsigned)worm->m_lev <= 3) ?
                   (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
@@ -403,14 +395,6 @@ cutworm(worm, x, y, weap)
        if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
     }
 
-    /* Add new monster to mon chain. */
-    new_worm->nmon = fmon;
-    fmon = new_worm;
-
-    /* Initialize the new worm. */
-    place_monster(new_worm, x, y);     /* put worm in level.monsters[][] */
-    newsym(x, y);                      /* make sure new worm shows up */
-
     wtails[new_wnum] = new_tail;       /* We've got all the info right now */
     wheads[new_wnum] = curr;           /* so we can do this faster than    */
     wgrowtime[new_wnum] = 0L;          /* trying to call initworm().       */
@@ -418,14 +402,10 @@ cutworm(worm, x, y, weap)
     /* Place the new monster at all the segment locations. */
     place_wsegs(new_worm);
 
-#if 0  /* long worms don't glow in the dark... */
-    if (emits_light(worm->data))
-       new_light_source(new_worm->mx, new_worm->my,
-                        emits_light(worm->data),
-                        LS_MONSTER, (genericptr_t)new_worm);
-#endif
-
-    You("cut %s in half.", mon_nam(worm));
+    if (context.mon_moving)
+       pline("%s is cut in half.", Monnam(worm));
+    else
+       You("cut %s in half.", mon_nam(worm));
 }