From: Pasi Kallinen Date: Thu, 2 Sep 2021 17:54:32 +0000 (+0300) Subject: Handle buried zombifying corpses X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cf44cb3382fa4b7e986501d0e9c40622ec55917b;p=nethack 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. --- diff --git a/src/do.c b/src/do.c index ac3a7f0ea..00b9b72b2 100644 --- a/src/do.c +++ b/src/do.c @@ -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); } } diff --git a/src/objnam.c b/src/objnam.c index bcf43ef49..d8ea61c2b 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -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); diff --git a/src/zap.c b/src/zap.c index bc57fb7b6..245968e64 100644 --- a/src/zap.c +++ b/src/zap.c @@ -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"); } diff --git a/test/testwish.lua b/test/testwish.lua index d28c82e3b..2fe5d869b 100644 --- a/test/testwish.lua +++ b/test/testwish.lua @@ -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 = "?" },