Skip to content

Commit

Permalink
Fix: two cases of Bifrost not being restored correctly
Browse files Browse the repository at this point in the history
First bug is issue #212: polymorphing the nemesis and then killing it
meant the killed_nemesis flag never got set, so level updates based on
that flag never triggered. The fix for this is to track the nemesis's
monster ID similar to how it works for the quest leader. This came with
a few tweaks:
- The nemesis's corpse will keep its monster traits.
- The nemesis cannot be tamed.
- You get the big alignment record bonus for killing them.
- They will still talk in their polymorphed form if their form is
  capable of speech.

The second bug involved if the player managed to kill Surtur before
loading Val-loca. This was because of an oversight when the
visited_after_event flag was added - it was not added in
clear_level_structures() and therefore the locate level was registering
as having already processed the post-Surtur-kill change.

Closes #212
  • Loading branch information
copperwater committed Jun 23, 2024
1 parent 37b10da commit dcd44cc
Show file tree
Hide file tree
Showing 9 changed files with 27 additions and 9 deletions.
2 changes: 2 additions & 0 deletions doc/xnh-changelog-9.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,5 @@ changes:

### Architectural changes

- The monster ID of the quest nemesis is now tracked similar to the quest
leader's.
1 change: 1 addition & 0 deletions include/quest.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct q_score { /* Quest "scorecard" */
Bitfield(godgend, 2); /* deity's gender */

unsigned leader_m_id;
unsigned nemesis_m_id;
};

#define MIN_QUEST_ALIGN 20 /* at least this align.record to start */
Expand Down
2 changes: 2 additions & 0 deletions src/dog.c
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,8 @@ tamedog(struct monst *mtmp, struct obj *obj, boolean pacify_only)

if (mtmp->m_id == gq.quest_status.leader_m_id)
return FALSE;
if (mtmp->m_id == gq.quest_status.nemesis_m_id)
return FALSE;

if (pacify_only) {
return FALSE;
Expand Down
2 changes: 2 additions & 0 deletions src/makemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,8 @@ makemon(
set_mon_data(mtmp, ptr); /* mtmp->data = ptr; */
if (ptr->msound == MS_LEADER && quest_info(MS_LEADER) == mndx)
gq.quest_status.leader_m_id = mtmp->m_id;
if (ptr->msound == MS_NEMESIS && quest_info(MS_NEMESIS) == mndx)
gq.quest_status.nemesis_m_id = mtmp->m_id;
mtmp->mnum = mndx;

/* set up level and hit points */
Expand Down
1 change: 1 addition & 0 deletions src/mklev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@ clear_level_structures(void)
gl.level.flags.arboreal = 0;
gl.level.flags.wizard_bones = 0;
gl.level.flags.outdoors = 0;
gl.level.flags.visited_after_event = 0;

gn.nroom = 0;
gr.rooms[0].hx = -1;
Expand Down
7 changes: 5 additions & 2 deletions src/mon.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,10 @@ pm_to_cham(int mndx)
#define KEEPTRAITS(mon) \
((mon)->isshk || (mon)->mtame || unique_corpstat((mon)->data) \
|| is_reviver((mon)->data) \
/* normally quest leader will be unique, */ \
/* normally quest leader/nemesis will be unique, */ \
/* but he or she might have been polymorphed */ \
|| (mon)->m_id == gq.quest_status.leader_m_id \
|| (mon)->m_id == gq.quest_status.nemesis_m_id \
/* special cancellation handling for these */ \
|| (dmgtype((mon)->data, AD_SEDU) || dmgtype((mon)->data, AD_SSEX)))

Expand Down Expand Up @@ -3091,6 +3092,8 @@ mondead(struct monst *mtmp)
/* if it's a (possibly polymorphed) quest leader, mark him as dead */
if (mtmp->m_id == gq.quest_status.leader_m_id)
gq.quest_status.killed_leader = TRUE;
if (mtmp->m_id == gq.quest_status.nemesis_m_id)
gq.quest_status.killed_nemesis = TRUE;
#ifdef MAIL_STRUCTURES
/* if the mail daemon dies, no more mail delivery. -3. */
if (mndx == PM_MAIL_DAEMON)
Expand Down Expand Up @@ -3680,7 +3683,7 @@ xkilled(
change_luck(-20);
pline("That was %sa bad idea...",
u.uevent.qcompleted ? "probably " : "");
} else if (mdat->msound == MS_NEMESIS) { /* Real good! */
} else if (mtmp->m_id == gq.quest_status.nemesis_m_id) { /* Real good! */
if (!gq.quest_status.killed_leader)
adjalign((int) (ALIGNLIM / 4));
} else if (mdat->msound == MS_GUARDIAN) { /* Bad */
Expand Down
14 changes: 8 additions & 6 deletions src/quest.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,11 @@ quest_chat(struct monst *mtmp)
setmangry(mtmp, FALSE);
return;
}
switch (mtmp->data->msound) {
case MS_NEMESIS:
if (mtmp->m_id == Qstat(nemesis_m_id) && mtmp->data->msound > MS_ANIMAL) {
chat_with_nemesis();
break;
return;
}
switch (mtmp->data->msound) {
case MS_GUARDIAN:
chat_with_guardian();
break;
Expand All @@ -500,10 +501,11 @@ quest_talk(struct monst *mtmp)
leader_speaks(mtmp);
return;
}
switch (mtmp->data->msound) {
case MS_NEMESIS:
if (mtmp->m_id == Qstat(nemesis_m_id) && mtmp->data->msound > MS_ANIMAL) {
nemesis_speaks();
break;
return;
}
switch (mtmp->data->msound) {
case MS_DJINNI:
prisoner_speaks(mtmp);
break;
Expand Down
2 changes: 2 additions & 0 deletions src/sounds.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,8 @@ domonnoise(register struct monst* mtmp)
/* leader might be poly'd; if he can still speak, give leader speech */
if (mtmp->m_id == gq.quest_status.leader_m_id && msound > MS_ANIMAL)
msound = MS_LEADER;
if (mtmp->m_id == gq.quest_status.nemesis_m_id && msound > MS_ANIMAL)
msound = MS_NEMESIS;
/* make sure it's your role's quest guardian; adjust if not */
else if (msound == MS_GUARDIAN && ptr != &mons[gu.urole.guardnum])
msound = mons[genus(monsndx(ptr), 1)].msound;
Expand Down
5 changes: 4 additions & 1 deletion src/zap.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,11 +723,14 @@ montraits(
(we cleared it when loading bones) */
if (mtmp->m_id) {
mtmp2->m_id = mtmp->m_id;
/* might be bringing quest leader back to life */
/* might be bringing quest leader/nemesis back to life */
if (gq.quest_status.killed_leader
/* killed_leader implies leader_m_id is valid */
&& mtmp2->m_id == gq.quest_status.leader_m_id)
gq.quest_status.killed_leader = FALSE;
if (gq.quest_status.killed_nemesis
&& mtmp2->m_id == gq.quest_status.nemesis_m_id)
gq.quest_status.killed_nemesis = FALSE;
}
mtmp2->mx = mtmp->mx;
mtmp2->my = mtmp->my;
Expand Down

0 comments on commit dcd44cc

Please sign in to comment.