diff --git a/src/makemon.c b/src/makemon.c index b2cb2c8a1..0f731c353 100644 --- a/src/makemon.c +++ b/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); }