Monsters can revive corpses on floor with undead turning

... but only if the corpse is in direct line from the monster to hero
This commit is contained in:
Pasi Kallinen
2020-12-11 19:49:21 +02:00
parent d5a8f783e0
commit ea93c17fa7
4 changed files with 98 additions and 31 deletions

View File

@@ -324,6 +324,8 @@ brown pudding monster hitting another monster with decay attack corroded armor
and ^A/re-do was suppressed due lack of obsolete '#define REDO'
add missing key binding support for rush.numpad; default is M-5 for numpad==1
or plain 5 for numpad==2 where behavior of 5 and M-5 are swapped
allow monsters to use wand of undead turning to revive corpses on floor
in some situations
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository

View File

@@ -1683,6 +1683,7 @@ E int FDECL(ohitmon, (struct monst *, struct obj *, int, BOOLEAN_P));
E void FDECL(thrwmu, (struct monst *));
E int FDECL(spitmu, (struct monst *, struct attack *));
E int FDECL(breamu, (struct monst *, struct attack *));
E boolean FDECL(linedup_callback, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, boolean FDECL((*), (int,int))));
E boolean FDECL(linedup, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, int));
E boolean FDECL(lined_up, (struct monst *));
E struct obj *FDECL(m_carrying, (struct monst *, int));

View File

@@ -969,6 +969,43 @@ struct attack *mattk;
return breamm(mtmp, mattk, &g.youmonst);
}
/* Move from (ax,ay) to (bx,by), but only if distance is up to BOLT_LIM
and only in straight line or diagonal, calling fnc for each step.
Stops if fnc return TRUE, or if step was blocked by wall or closed door.
Returns TRUE if fnc returned TRUE. */
boolean
linedup_callback(ax, ay, bx, by, fnc)
xchar ax, ay, bx, by;
boolean FDECL((*fnc), (int, int));
{
int dx, dy;
/* These two values are set for use after successful return. */
g.tbx = ax - bx;
g.tby = ay - by;
/* sometimes displacement makes a monster think that you're at its
own location; prevent it from throwing and zapping in that case */
if (!g.tbx && !g.tby)
return FALSE;
if ((!g.tbx || !g.tby || abs(g.tbx) == abs(g.tby)) /* straight line or diagonal */
&& distmin(g.tbx, g.tby, 0, 0) < BOLT_LIM) {
dx = sgn(ax - bx), dy = sgn(ay - by);
do {
/* <bx,by> is guaranteed to eventually converge with <ax,ay> */
bx += dx, by += dy;
if (!isok(bx, by))
return FALSE;
if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
return FALSE;
if ((*fnc)(bx, by))
return TRUE;
} while (bx != ax || by != ay);
}
return FALSE;
}
boolean
linedup(ax, ay, bx, by, boulderhandling)
register xchar ax, ay, bx, by;

View File

@@ -20,6 +20,8 @@ static void FDECL(mplayhorn, (struct monst *, struct obj *, BOOLEAN_P));
static void FDECL(mreadmsg, (struct monst *, struct obj *));
static void FDECL(mquaffmsg, (struct monst *, struct obj *));
static boolean FDECL(m_use_healing, (struct monst *));
static boolean FDECL(linedup_chk_corpse, (int, int));
static void FDECL(m_use_undead_turning, (struct monst *, struct obj *));
static int FDECL(mbhitm, (struct monst *, struct obj *));
static void FDECL(mbhit, (struct monst *, int,
int FDECL((*), (MONST_P, OBJ_P)),
@@ -1134,6 +1136,60 @@ struct monst *mtmp;
/*#define MUSE_WAN_UNDEAD_TURNING 20*/ /* also a defensive item so don't
* redefine; nonconsecutive value is ok */
static boolean
linedup_chk_corpse(x, y)
int x, y;
{
return (sobj_at(CORPSE, x, y) != 0);
}
static void
m_use_undead_turning(mtmp, obj)
struct monst *mtmp;
struct obj *obj;
{
int ax = u.ux + sgn(mtmp->mux - mtmp->mx) * 3,
ay = u.uy + sgn(mtmp->muy - mtmp->my) * 3;
int bx = mtmp->mx, by = mtmp->my;
if (!(obj->otyp == WAN_UNDEAD_TURNING && obj->spe > 0))
return;
/* not necrophiliac(); unlike deciding whether to pick this
type of wand up, we aren't interested in corpses within
carried containers until they're moved into open inventory;
we don't check whether hero is poly'd into an undead--the
wand's turning effect is too weak to be a useful direct
attack--only whether hero is carrying at least one corpse */
if (carrying(CORPSE)) {
/*
* Hero is carrying one or more corpses but isn't wielding
* a cockatrice corpse (unless being hit by one won't do
* the monster much harm); otherwise we'd be using this wand
* as a defensive item with higher priority.
*
* Might be cockatrice intended as a weapon (or being denied
* to glove-wearing monsters for use as a weapon) or lizard
* intended as a cure or lichen intended as veggy food or
* sacrifice fodder being lugged to an altar. Zapping with
* this will deprive hero of one from each stack although
* they might subsequently be recovered after killing again.
* In the sacrifice fodder case, it could even be to the
* player's advantage (fresher corpse if a new one gets
* dropped; player might not choose to spend a wand charge
* on that when/if hero acquires this wand).
*/
g.m.offensive = obj;
g.m.has_offense = MUSE_WAN_UNDEAD_TURNING;
} else if (linedup_callback(ax, ay, bx, by, linedup_chk_corpse)) {
/* There's a corpse on the ground in a direct line from the
* monster to the hero, and up to 3 steps beyond.
*/
g.m.offensive = obj;
g.m.has_offense = MUSE_WAN_UNDEAD_TURNING;
}
}
/* Select an offensive item/action for a monster. Returns TRUE iff one is
* found.
*/
@@ -1208,34 +1264,7 @@ struct monst *mtmp;
}
}
nomore(MUSE_WAN_UNDEAD_TURNING);
if (obj->otyp == WAN_UNDEAD_TURNING && obj->spe > 0
/* not necrophiliac(); unlike deciding whether to pick this
type of wand up, we aren't interested in corpses within
carried containers until they're moved into open inventory;
we don't check whether hero is poly'd into an undead--the
wand's turning effect is too weak to be a useful direct
attack--only whether hero is carrying at least one corpse */
&& carrying(CORPSE)) {
/*
* Hero is carrying one or more corpses but isn't wielding
* a cockatrice corpse (unless being hit by one won't do
* the monster much harm); otherwise we'd be using this wand
* as a defensive item with higher priority.
*
* Might be cockatrice intended as a weapon (or being denied
* to glove-wearing monsters for use as a weapon) or lizard
* intended as a cure or lichen intended as veggy food or
* sacrifice fodder being lugged to an altar. Zapping with
* this will deprive hero of one from each stack although
* they might subsequently be recovered after killing again.
* In the sacrifice fodder case, it could even be to the
* player's advantage (fresher corpse if a new one gets
* dropped; player might not choose to spend a wand charge
* on that when/if hero acquires this wand).
*/
g.m.offensive = obj;
g.m.has_offense = MUSE_WAN_UNDEAD_TURNING;
}
m_use_undead_turning(mtmp, obj);
nomore(MUSE_WAN_STRIKING);
if (obj->otyp == WAN_STRIKING && obj->spe > 0) {
g.m.offensive = obj;
@@ -2342,11 +2371,9 @@ struct obj *obj;
if (typ == WAN_POLYMORPH)
return (boolean) (mons[monsndx(mon->data)].difficulty < 6);
if (objects[typ].oc_dir == RAY || typ == WAN_STRIKING
|| typ == WAN_UNDEAD_TURNING
|| typ == WAN_TELEPORTATION || typ == WAN_CREATE_MONSTER)
return TRUE;
if (typ == WAN_UNDEAD_TURNING)
return (necrophiliac(g.invent, TRUE)
|| (Upolyd && is_undead(g.youmonst.data)));
break;
case POTION_CLASS:
if (typ == POT_HEALING || typ == POT_EXTRA_HEALING