makemon() and clone_mon()
Express the logic of various early returns more consistently. clone_mon() wasn't handling mon->isminion correctly. I'm not sure whether it is actually possible to clone a minion (maybe after polymorphing it into a gremlin or blue jelly?). When it wasn't tame, which is the case for every minion other than the guardian angel on Astral, the emin structure wasn't being allocated for the clone but its isminion flag was left set. Also, clones inherited mon->mtrack[] so would unnecessarily avoid moving onto spots the original had recently moved across. Cloned pets are inheriting various pet-specific fields that they probably should be starting with a clean slate on but I haven't made any attempt to address that.
This commit is contained in:
123
src/makemon.c
123
src/makemon.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 makemon.c $NHDT-Date: 1559733390 2019/06/05 11:16:30 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.137 $ */
|
||||
/* NetHack 3.6 makemon.c $NHDT-Date: 1561236435 2019/06/22 20:47:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.138 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2012. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -819,18 +819,20 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (!isok(mm.x, mm.y)) { /* paranoia */
|
||||
impossible("clone_mon trying to create a monster at <%d,%d>?",
|
||||
mm.x, mm.y);
|
||||
return (struct monst *) 0;
|
||||
}
|
||||
if (MON_AT(mm.x, mm.y)) { /* (always True for the x==0 case) */
|
||||
if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
|
||||
return (struct monst *) 0;
|
||||
}
|
||||
|
||||
m2 = newmonst();
|
||||
*m2 = *mon; /* copy condition of old monster */
|
||||
m2->mextra = (struct mextra *) 0;
|
||||
@@ -846,7 +848,7 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
|
||||
m2->mtrapped = 0;
|
||||
m2->mcloned = 1;
|
||||
m2->minvent = (struct obj *) 0; /* objects don't clone */
|
||||
m2->mleashed = FALSE;
|
||||
m2->mleashed = 0;
|
||||
/* Max HP the same, but current HP halved for both. The caller
|
||||
* might want to override this by halving the max HP also.
|
||||
* When current HP is odd, the original keeps the extra point.
|
||||
@@ -856,21 +858,20 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
|
||||
m2->mhp = mon->mhp / 2;
|
||||
mon->mhp -= m2->mhp;
|
||||
|
||||
/* since shopkeepers and guards will only be cloned if they've been
|
||||
* polymorphed away from their original forms, the clone doesn't have
|
||||
* room for the extra information. we also don't want two shopkeepers
|
||||
* around for the same shop.
|
||||
*/
|
||||
if (mon->isshk)
|
||||
m2->isshk = FALSE;
|
||||
if (mon->isgd)
|
||||
m2->isgd = FALSE;
|
||||
if (mon->ispriest)
|
||||
m2->ispriest = FALSE;
|
||||
/* clone doesn't have mextra so mustn't retain special monster flags */
|
||||
m2->isshk = 0;
|
||||
m2->isgd = 0;
|
||||
m2->ispriest = 0;
|
||||
/* ms->isminion handled below */
|
||||
|
||||
/* clone shouldn't be reluctant to move on spots 'parent' just moved on */
|
||||
(void) memset((genericptr_t) m2->mtrack, 0, sizeof m2->mtrack);
|
||||
|
||||
place_monster(m2, m2->mx, m2->my);
|
||||
if (emits_light(m2->data))
|
||||
new_light_source(m2->mx, m2->my, emits_light(m2->data), LS_MONSTER,
|
||||
monst_to_any(m2));
|
||||
/* if 'parent' is named, give the clone the same name */
|
||||
if (has_mname(mon)) {
|
||||
m2 = christen_monst(m2, MNAME(mon));
|
||||
} else if (mon->isshk) {
|
||||
@@ -878,31 +879,35 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
|
||||
}
|
||||
|
||||
/* not all clones caused by player are tame or peaceful */
|
||||
if (!context.mon_moving) {
|
||||
if (!context.mon_moving && mon->mpeaceful) {
|
||||
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;
|
||||
}
|
||||
/* if guardian angel could be cloned (maybe after polymorph?),
|
||||
m2 could be both isminion and mtame; isminion takes precedence */
|
||||
if (m2->isminion) {
|
||||
int atyp;
|
||||
|
||||
newsym(m2->mx, m2->my); /* display the new monster */
|
||||
if (m2->mtame) {
|
||||
if (mon->isminion) {
|
||||
newemin(m2);
|
||||
if (EMIN(mon))
|
||||
*(EMIN(m2)) = *(EMIN(mon));
|
||||
} else {
|
||||
/* because m2 is a copy of mon it is tame but not init'ed.
|
||||
* however, tamedog will not re-tame a tame dog, so m2
|
||||
* must be made non-tame to get initialized properly.
|
||||
*/
|
||||
m2->mtame = 0;
|
||||
if (tamedog(m2, (struct obj *) 0)) {
|
||||
*(EDOG(m2)) = *(EDOG(mon));
|
||||
}
|
||||
}
|
||||
newemin(m2);
|
||||
*EMIN(m2) = *EMIN(mon);
|
||||
/* renegade when same alignment as hero but not peaceful or
|
||||
when peaceful while being different alignment from hero */
|
||||
atyp = EMIN(m2)->min_align;
|
||||
EMIN(m2)->renegade = (atyp != u.ualign.type) ^ !m2->mpeaceful;
|
||||
} else if (m2->mtame) {
|
||||
/* Because m2 is a copy of mon it is tame but not init'ed.
|
||||
However, tamedog() will not re-tame a tame dog, so m2
|
||||
must be made non-tame to get initialized properly. */
|
||||
m2->mtame = 0;
|
||||
if (tamedog(m2, (struct obj *) 0))
|
||||
*EDOG(m2) = *EDOG(mon);
|
||||
/* [TODO? some (most? all?) edog fields probably should be
|
||||
reinitialized rather that retain the 'parent's values] */
|
||||
}
|
||||
set_malign(m2);
|
||||
newsym(m2->mx, m2->my); /* display the new monster */
|
||||
|
||||
return m2;
|
||||
}
|
||||
@@ -1107,6 +1112,8 @@ register int x, y;
|
||||
int mmflags;
|
||||
{
|
||||
register struct monst *mtmp;
|
||||
struct monst fakemon;
|
||||
coord cc;
|
||||
int mndx, mcham, ct, mitem;
|
||||
boolean anymon = (!ptr);
|
||||
boolean byyou = (x == u.ux && y == u.uy);
|
||||
@@ -1114,40 +1121,37 @@ int mmflags;
|
||||
boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
|
||||
unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0;
|
||||
|
||||
fakemon = zeromonst;
|
||||
cc.x = cc.y = 0;
|
||||
|
||||
/* if caller wants random location, do it here */
|
||||
if (x == 0 && y == 0) {
|
||||
coord cc;
|
||||
struct monst fakemon;
|
||||
|
||||
cc.x = cc.y = 0; /* lint suppression */
|
||||
fakemon = zeromonst;
|
||||
fakemon.data = ptr; /* set up for goodpos */
|
||||
if (!makemon_rnd_goodpos(ptr ? &fakemon : (struct monst *)0,
|
||||
if (!makemon_rnd_goodpos(ptr ? &fakemon : (struct monst *) 0,
|
||||
gpflags, &cc))
|
||||
return (struct monst *) 0;
|
||||
x = cc.x;
|
||||
y = cc.y;
|
||||
} else if (byyou && !in_mklev) {
|
||||
coord bypos;
|
||||
|
||||
if (enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) {
|
||||
x = bypos.x;
|
||||
y = bypos.y;
|
||||
} else
|
||||
if (!enexto_core(&cc, u.ux, u.uy, ptr, gpflags))
|
||||
return (struct monst *) 0;
|
||||
x = cc.x;
|
||||
y = cc.y;
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (!isok(x, y)) {
|
||||
impossible("makemon trying to create a monster at <%d,%d>?", x, y);
|
||||
return (struct monst *) 0;
|
||||
}
|
||||
|
||||
/* Does monster already exist at the position? */
|
||||
if (MON_AT(x, y)) {
|
||||
if ((mmflags & MM_ADJACENTOK) != 0) {
|
||||
coord bypos;
|
||||
if (enexto_core(&bypos, x, y, ptr, gpflags)) {
|
||||
x = bypos.x;
|
||||
y = bypos.y;
|
||||
} else
|
||||
return (struct monst *) 0;
|
||||
} else
|
||||
if (!(mmflags & MM_ADJACENTOK)
|
||||
|| !enexto_core(&cc, x, y, ptr, gpflags))
|
||||
return (struct monst *) 0;
|
||||
x = cc.x;
|
||||
y = cc.y;
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
@@ -1167,7 +1171,6 @@ int mmflags;
|
||||
* for instance.)
|
||||
*/
|
||||
int tryct = 0; /* maybe there are no good choices */
|
||||
struct monst fakemon;
|
||||
|
||||
do {
|
||||
if (!(ptr = rndmonst())) {
|
||||
@@ -1354,6 +1357,7 @@ int mmflags;
|
||||
? !(mmflags & (MM_EPRI | MM_EMIN))
|
||||
: (mndx == PM_ANGEL && !(mmflags & MM_EMIN) && !rn2(3))) {
|
||||
struct emin *eminp;
|
||||
|
||||
newemin(mtmp);
|
||||
eminp = EMIN(mtmp);
|
||||
|
||||
@@ -1385,6 +1389,7 @@ int mmflags;
|
||||
if (!rn2(100) && is_domestic(ptr)
|
||||
&& can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
|
||||
struct obj *otmp = mksobj(SADDLE, TRUE, FALSE);
|
||||
|
||||
put_saddle_on_mon(otmp, mtmp);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user