Handle buried zombifying corpses

When a zombifying corpse is buried, allow it to zombify and
dig itself out of the ground.

Also allow wishing for zombifying corpses.
This commit is contained in:
Pasi Kallinen
2021-09-02 20:54:32 +03:00
parent 43db84cd13
commit cf44cb3382
4 changed files with 63 additions and 4 deletions

View File

@@ -1848,6 +1848,7 @@ revive_corpse(struct obj *corpse)
char cname[BUFSZ];
struct obj *container = (struct obj *) 0;
int container_where = 0;
boolean is_zomb = (mons[corpse->corpsenm].mlet == S_ZOMBIE);
where = corpse->where;
is_uwep = (corpse == uwep);
@@ -1915,6 +1916,21 @@ revive_corpse(struct obj *corpse)
}
break;
}
case OBJ_BURIED:
if (is_zomb) {
maketrap(mtmp->mx, mtmp->my, PIT);
if (cansee(mtmp->mx, mtmp->my)) {
struct trap *ttmp;
ttmp = t_at(mtmp->mx, mtmp->my);
ttmp->tseen = TRUE;
pline("%s claws itself out of the ground!", Amonnam(mtmp));
newsym(mtmp->mx, mtmp->my);
} else if (distu(mtmp->mx, mtmp->my) < 5*5)
You_hear("scratching noises.");
break;
}
/*FALLTHRU*/
default:
/* we should be able to handle the other cases... */
impossible("revive_corpse: lost corpse @ %d", where);
@@ -1961,13 +1977,15 @@ revive_mon(anything *arg, long timeout UNUSED)
action = REVIVE_MON;
when = rider_revival_time(body, TRUE);
} else { /* rot this corpse away */
You_feel("%sless hassled.", is_rider(mptr) ? "much " : "");
if (!obj_has_timer(body, ROT_CORPSE))
You_feel("%sless hassled.", is_rider(mptr) ? "much " : "");
action = ROT_CORPSE;
when = (long) d(5, 50) - (g.moves - body->age);
if (when < 1L)
when = 1L;
}
(void) start_timer(when, TIMER_OBJECT, action, arg);
if (!obj_has_timer(body, action))
(void) start_timer(when, TIMER_OBJECT, action, arg);
}
}

View File

@@ -27,6 +27,7 @@ struct _readobjnam_data {
int tmp, tinv, tvariety, mgend;
int wetness, gsize;
int ftype;
boolean zombify;
char globbuf[BUFSZ];
char fruitbuf[BUFSZ];
};
@@ -3317,6 +3318,7 @@ readobjnam_init(char *bp, struct _readobjnam_data *d)
d->actualn = d->dn = d->un = 0;
d->wetness = 0;
d->gsize = 0;
d->zombify = FALSE;
d->bp = d->origbp = bp;
d->p = (char *) 0;
d->name = (const char *) 0;
@@ -3432,6 +3434,8 @@ readobjnam_preparse(struct _readobjnam_data *d)
d->looted = 1;
} else if (!strncmpi(d->bp, "greased ", l = 8)) {
d->isgreased = 1;
} else if (!strncmpi(d->bp, "zombifying ", l = 11)) {
d->zombify = TRUE;
} else if (!strncmpi(d->bp, "very ", l = 5)) {
/* very rusted very heavy iron ball */
d->very = 1;
@@ -4499,6 +4503,10 @@ readobjnam(char *bp, struct obj *no_wish)
d.mntmp = genus(d.mntmp, 1);
set_corpsenm(d.otmp, d.mntmp);
}
if (d.zombify && zombie_form(&mons[d.mntmp])) {
(void) start_timer(rn1(5, 10), TIMER_OBJECT,
ZOMBIFY_MON, obj_to_any(d.otmp));
}
break;
case EGG:
d.mntmp = can_be_hatched(d.mntmp);

View File

@@ -12,6 +12,7 @@
*/
#define MAGIC_COOKIE 1000
static boolean zombie_can_dig(xchar x, xchar y);
static void polyuse(struct obj *, int, int);
static void create_polymon(struct obj *, int);
static int stone_to_flesh_obj(struct obj *);
@@ -742,6 +743,22 @@ get_container_location(struct obj *obj, int *loc, int *container_nesting)
return (struct monst *) 0;
}
/* can zombie dig the location at x,y */
static boolean
zombie_can_dig(xchar x, xchar y)
{
if (isok(x,y)) {
schar typ = levl[x][y].typ;
struct trap *ttmp;
if ((ttmp = t_at(x, y)) != 0)
return FALSE;
if (typ == ROOM || typ == CORR || typ == GRAVE)
return TRUE;
}
return FALSE;
}
/*
* Attempt to revive the given corpse, return the revived monster if
* successful. Note: this does NOT use up the corpse if it fails.
@@ -759,6 +776,7 @@ revive(struct obj *corpse, boolean by_hero)
boolean one_of;
long mmflags = NO_MINVENT | MM_NOWAIT;
int montype, cgend, container_nesting = 0;
boolean is_zomb = (mons[corpse->corpsenm].mlet == S_ZOMBIE);
if (corpse->otyp != CORPSE) {
impossible("Attempting to revive %s?", xname(corpse));
@@ -767,9 +785,11 @@ revive(struct obj *corpse, boolean by_hero)
x = y = 0;
if (corpse->where != OBJ_CONTAINED) {
/* only for invent, minvent, or floor */
int locflags = is_zomb ? BURIED_TOO : 0;
/* only for invent, minvent, or floor, or if zombie, buried */
container = 0;
(void) get_obj_location(corpse, &x, &y, 0);
(void) get_obj_location(corpse, &x, &y, locflags);
} else {
/* deal with corpses in [possibly nested] containers */
struct monst *carrier;
@@ -804,6 +824,10 @@ revive(struct obj *corpse, boolean by_hero)
|| (container->otyp == BAG_OF_HOLDING && rn2(40)))))
return (struct monst *) 0;
/* buried zombie cannot dig itself out, do not revive */
if (is_zomb && corpse->where == OBJ_BURIED && !zombie_can_dig(x, y))
return (struct monst *) 0;
/* record the object's location now that we're sure where it is */
corpse->ox = x, corpse->oy = y;
@@ -977,6 +1001,13 @@ revive(struct obj *corpse, boolean by_hero)
obj_extract_self(corpse);
obfree(corpse, (struct obj *) 0);
break;
case OBJ_BURIED:
if (is_zomb) {
obj_extract_self(corpse);
obfree(corpse, (struct obj *) 0);
break;
}
/*FALLTHRU*/
default:
panic("revive");
}

View File

@@ -39,6 +39,8 @@ local wishtest_objects = {
["spinach"] = { otyp_name = "tin", oclass = "%", corpsenm = -1, spe = 1 },
["trapped tin of floating eye meat"] = { otyp_name = "tin", oclass = "%", otrapped = 1, corpsenm_name = "floating eye" },
["hill orc corpse"] = { otyp_name = "corpse", oclass = "%", corpsenm_name = "hill orc" },
-- TODO: zombifying and other timers cannot be seen via lua
["zombifying elf corpse"] = { otyp_name = "corpse", oclass = "%", corpsenm_name = "elf" },
["destroy armor"] = { otyp_name = "destroy armor", oclass = "?" },
["enchant weapon"] = { otyp_name = "enchant weapon", oclass = "?" },
["scroll of food detection"] = { otyp_name = "food detection", oclass = "?" },