Skip to content

Commit

Permalink
Save compat for the Beogh/priest polymorph bug
Browse files Browse the repository at this point in the history
See e6d7efa for the bug itself.

This cleans up duplicate mid monsters for various cases that match the
conditions of this bug. Possibly this should have a minor version tag
bump, but as of right now that will mess up the ghost permastores and I
don't want to do that this close to a release.
  • Loading branch information
rawlins committed Jul 18, 2018
1 parent 337e1da commit eb4a410
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 0 deletions.
21 changes: 21 additions & 0 deletions crawl-ref/source/god-companions.cc
Expand Up @@ -12,6 +12,7 @@
#include "branch.h"
#include "dgn-overview.h"
#include "message.h"
#include "mon-death.h"
#include "mon-util.h"
#include "religion.h"
#include "spl-other.h"
Expand Down Expand Up @@ -265,4 +266,24 @@ void fixup_bad_companions()
++i;
}
}

bool maybe_bad_priest_monster(monster &mons)
{
// prior to e6d7efa92cb0, if a follower got polymorphed to a form that
// satisfied is_priest, its god got cleared. This resulted in Beogh
// followers potentially getting cloned on level load, resulting in
// duplicate mids or a corrupted mid cache depending on ordering. This is
// now fixed up in tag_read_level_load.
return mons.alive() && mons.attitude == ATT_FRIENDLY
&& mons.god == GOD_NAMELESS;
}

void fixup_bad_priest_monster(monster &mons)
{
if (!maybe_bad_priest_monster(mons))
return;
mprf(MSGCH_ERROR, "Removing corrupted ex-follower from level: %s.",
mons.full_name(DESC_PLAIN).c_str());
monster_die(mons, KILL_RESET, -1, true, false);
}
#endif
2 changes: 2 additions & 0 deletions crawl-ref/source/god-companions.h
Expand Up @@ -44,4 +44,6 @@ monster* hepliaklqana_ancestor_mon();

#if TAG_MAJOR_VERSION == 34
void fixup_bad_companions();
bool maybe_bad_priest_monster(monster &mons);
void fixup_bad_priest_monster(monster &mons);
#endif
9 changes: 9 additions & 0 deletions crawl-ref/source/mon-transit.cc
Expand Up @@ -253,6 +253,15 @@ monster* follower::place(bool near_player)

if (m->find_place_to_live(near_player))
{
#if TAG_MAJOR_VERSION == 34
// fix up some potential cloned monsters for beogh chars.
// see comments on maybe_bad_priest monster and in tags.cc for details
monster *dup_m = monster_by_mid(m->mid);
if (dup_m && maybe_bad_priest_monster(*dup_m))
fixup_bad_priest_monster(*dup_m);
// any clones not covered under maybe_bad_priest_monster will result
// in duplicate mid errors.
#endif
dprf("Placed follower: %s", m->name(DESC_PLAIN, true).c_str());
m->target.reset();

Expand Down
26 changes: 26 additions & 0 deletions crawl-ref/source/tags.cc
Expand Up @@ -6439,6 +6439,32 @@ static void tag_read_level_monsters(reader &th)
if (!m.alive())
continue;

#if TAG_MAJOR_VERSION == 34
// clear duplicates of followers who got their god cleared as the result
// of a bad polymorph prior to e6d7efa92cb0. This only fires on level
// load *when there are duplicate mids*, because otherwise the clones
// aren't uniquely identifiable. This fix may still result in duplicate
// mid errors from time to time, but should never crash; saving and
// loading will fix up the duplicate errors. A similar check also
// happens in follower::place (since that runs after the level is
// loaded).
monster *dup_m = monster_by_mid(m.mid);
if (dup_m)
{
if (maybe_bad_priest_monster(*dup_m))
fixup_bad_priest_monster(*dup_m);
else if (maybe_bad_priest_monster(m))
{
fixup_bad_priest_monster(m);
env.mid_cache[dup_m->mid] = dup_m->mindex();
// dup_m should already be placed, so nothing else is needed.
continue;
}
// we could print an error on the else case, but this is already
// going to be handled by debug_mons_scan.
}
#endif

// companion_is_elsewhere checks the mid cache
env.mid_cache[m.mid] = i;
if (m.is_divine_companion() && companion_is_elsewhere(m.mid))
Expand Down

0 comments on commit eb4a410

Please sign in to comment.