From 43c302d9274578d1ad727db0c0a688d1a898306f Mon Sep 17 00:00:00 2001 From: copperwater Date: Sun, 21 Jun 2026 06:02:20 -0400 Subject: [PATCH] Copy bones monster info to recorporealized ghost This is a reimplementation of commit ec32748 in TNNT by entrez: If you use undead turning on a dead hero's corpse from a bones file, its ghost will get sucked back into its body when it comes back to life. In such cases, treat the newly revived corpse/recorporealized ghost as a "former hero" for the purposes of livelogging bones monster kills. Part of this change was to remove a bit of weirdness in the game - the odd situation where you revive a corpse-ghost combo on a bones pile, and get the messages: The human corpse glows iridescently. Foo's ghost is suddenly drawn into its former body! The human is resurrected! and subsequently the monster is just a generic human (or elf, etc) without anything indicating it used to be a player. With this change, the monster will retain the name that the ghost had, and its struct ebones prevents the player from renaming it. This commit also adjusts the "resurrected" message to explicitly use the monster's name if it has one, and to use YMonnam in the unrelated case where the monster was a pet (so reviving an unnamed tame kitten will print as "Your kitten is resurrected!") --- src/zap.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/zap.c b/src/zap.c index 3e578fbee..dca9a97c0 100644 --- a/src/zap.c +++ b/src/zap.c @@ -892,6 +892,10 @@ revive(struct obj *corpse, boolean by_hero) mmflags_nht mmflags = NO_MINVENT | MM_NOWAIT | MM_NOMSG; int montype, cgend, container_nesting = 0; boolean is_zomb; + /* normally use the name on the corpse object, but don't if drawing a + * player's ghost back into its body, in which case use the ghost's + * (player's) name */ + boolean use_corpse_name = TRUE; if (corpse->otyp != CORPSE) { impossible("Attempting to revive %s?", xname(corpse)); @@ -1085,6 +1089,16 @@ revive(struct obj *corpse, boolean by_hero) mtmp->mtame = ghost->mtame; } } + /* copy over ghost's name and struct ebones to newly revived "hero"; + * has_mgivenname should always be true because there are guards + * against renaming a ghost, but check it just to be sure */ + if (has_mgivenname(ghost)) { + mtmp = christen_monst(mtmp, MGIVENNAME(ghost)); + /* don't let player-provided name of corpse override actual + * name of ex-hero */ + use_corpse_name = FALSE; + } + copy_mextra(mtmp, ghost); /* pass on struct ebones */ /* was ghost, now alive, it's all very confusing */ mtmp->mconf = 1; /* separate ghost monster no longer exists */ @@ -1094,7 +1108,7 @@ revive(struct obj *corpse, boolean by_hero) } /* monster retains its name */ - if (has_oname(corpse) && !unique_corpstat(mtmp->data)) + if (use_corpse_name && has_oname(corpse) && !unique_corpstat(mtmp->data)) mtmp = christen_monst(mtmp, ONAME(corpse)); /* partially eaten corpse yields wounded monster */ if (corpse->oeaten) @@ -2357,7 +2371,7 @@ bhito(struct obj *obj, struct obj *otmp) if (cansee(ox, oy)) { if (canspotmon(mtmp)) { pline("%s is resurrected!", - upstart(noname_monnam(mtmp, ARTICLE_THE))); + mtmp->mtame ? YMonnam(mtmp) : Monnam(mtmp)); learn_it = by_u ? TRUE : gz.zap_oseen; } else { /* saw corpse but don't see monster: maybe