From: cohrs Date: Thu, 23 Oct 2003 02:30:46 +0000 (+0000) Subject: buglist: cutting Shopkeeper the long worm X-Git-Tag: MOVE2GIT~1655 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f4fbe1a13e9660f054d485dd9a555f12081b8849;p=nethack buglist: cutting Shopkeeper the long worm 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) --- diff --git a/doc/fixes34.3 b/doc/fixes34.3 index ba2a7c765..75aee3998 100644 --- a/doc/fixes34.3 +++ b/doc/fixes34.3 @@ -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 diff --git a/include/extern.h b/include/extern.h index 89c4e6d56..8a024a3db 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/src/makemon.c b/src/makemon.c index a6cd84f42..f4337b48a 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -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; } diff --git a/src/mhitm.c b/src/mhitm.c index 717dec170..3e2a3592a 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -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]; diff --git a/src/potion.c b/src/potion.c index 5c1dff265..788293a63 100644 --- a/src/potion.c +++ b/src/potion.c @@ -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; diff --git a/src/uhitm.c b/src/uhitm.c index 6f115ba85..ebe8cebd5 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -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; } diff --git a/src/worm.c b/src/worm.c index 3d7a32763..a965f948c 100644 --- a/src/worm.c +++ b/src/worm.c @@ -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)); }