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)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
42
src/worm.c
42
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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user