summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/dactions.cc
diff options
context:
space:
mode:
authorblackcustard <peterwicksstringfield@gmail.com>2013-07-30 14:11:30 -0500
committerNeil Moore <neil@s-z.org>2013-07-30 16:36:15 -0400
commited92a994f664c3d06841dd45e2479d5c037e3316 (patch)
tree408791ee412f79361cc0d5f94aea0e248e473dff /crawl-ref/source/dactions.cc
parentc67cb32cf693618954cf9a0211d99e07e5ed05b4 (diff)
downloadcrawl-ref-ed92a994f664c3d06841dd45e2479d5c037e3316.tar.gz
crawl-ref-ed92a994f664c3d06841dd45e2479d5c037e3316.zip
Fix a Kirke crash by deporkalating transiting hogs correctly.
Normally, monsters are stored in a list (env.mons or menv for short). There is a grid (env.mgrid or mgrd for short) which maps the position (x, y) of the monster to its index in the list. Transiting monsters, however, exist outside both the monster list and the monster grid. They are stored separately, and they do not really have positions. The deporkalation code inside dactions.cc was not transiting-monster aware. It would call monster::move_to_pos on transiting hogs, just as on non-transiting hogs. When it did so, it would write their index inside the monster list into the monster grid. Of course, since these hogs were not in the monster list in the first place, this "index" was bogus. Within a few turns one of several unrelated parts Crawl would try to investigate the monster grid and trip over the bogus entry, triggering this assertion in monster_at inside mon-util.cc: ASSERT(mindex <= MAX_MONSTERS); Changes: 1. Make the deporkalation code transiting-monster aware. Do not call monster::move_to_pos on transiting monsters. (Fixes the crash.) 2. Add some informative comments. 3. Make an implicit type conversion from monster to follower explicit.
Diffstat (limited to 'crawl-ref/source/dactions.cc')
-rw-r--r--crawl-ref/source/dactions.cc34
1 files changed, 25 insertions, 9 deletions
diff --git a/crawl-ref/source/dactions.cc b/crawl-ref/source/dactions.cc
index eb6428b161..2b53f32d90 100644
--- a/crawl-ref/source/dactions.cc
+++ b/crawl-ref/source/dactions.cc
@@ -23,7 +23,7 @@
#include "travel.h"
#include "view.h"
-static void _daction_hog_to_human(monster *mon);
+static void _daction_hog_to_human(monster *mon, bool in_transit);
#ifdef DEBUG_DIAGNOSTICS
static const char *daction_names[] =
@@ -161,8 +161,13 @@ void add_daction(daction_type act)
}
-void apply_daction_to_mons(monster* mon, daction_type act, bool local)
+void apply_daction_to_mons(monster* mon, daction_type act, bool local,
+ bool in_transit)
{
+ // Transiting monsters exist outside the normal monster list (env.mons or
+ // menv for short). Be careful not to write them into the monster grid, by,
+ // for example, calling monster::move_to_pos on them.
+ // See _daction_hog_to_human for an example.
switch (act)
{
case DACT_ALLY_HOLY:
@@ -221,7 +226,7 @@ void apply_daction_to_mons(monster* mon, daction_type act, bool local)
break;
case DACT_KIRKE_HOGS:
- _daction_hog_to_human(mon);
+ _daction_hog_to_human(mon, in_transit);
break;
case DACT_END_SPIRIT_HOWL:
@@ -265,7 +270,7 @@ static void _apply_daction(daction_type act)
for (monster_iterator mi; mi; ++mi)
{
if (mons_matches_daction(*mi, act))
- apply_daction_to_mons(*mi, act, true);
+ apply_daction_to_mons(*mi, act, true, false);
}
break;
@@ -308,7 +313,7 @@ unsigned int query_da_counter(daction_type c)
return travel_cache.query_da_counter(c) + count_daction_in_transit(c);
}
-static void _daction_hog_to_human(monster *mon)
+static void _daction_hog_to_human(monster *mon, bool in_transit)
{
// Hogs to humans
monster orig;
@@ -317,19 +322,21 @@ static void _daction_hog_to_human(monster *mon)
// Was it a converted monster or original band member?
if (mon->props.exists(ORIG_MONSTER_KEY))
{
- // Copy it, since the instance in props will get deleted
- // as soon a **mi is assigned to.
+ // It was transformed into a pig. Copy it, since the instance in props
+ // will get deleted as soon a **mi is assigned to.
orig = mon->props[ORIG_MONSTER_KEY].get_monster();
orig.mid = mon->mid;
}
else
{
+ // It started life as a pig in Kirke's band.
orig.type = MONS_HUMAN;
orig.attitude = mon->attitude;
orig.mid = mon->mid;
define_monster(&orig);
}
- // Keep at same spot.
+ // Keep at same spot. This position is irrelevant if the hog is in transit.
+ // See below.
const coord_def pos = mon->pos();
// Preserve relative HP.
const float hp
@@ -343,7 +350,16 @@ static void _daction_hog_to_human(monster *mon)
// Restore original monster.
*mon = orig;
- mon->move_to_pos(pos);
+ // If the hog is in transit, then it is NOT stored in the normal
+ // monster list (env.mons or menv for short). We cannot call move_to_pos
+ // on such a hog, because move_to_pos will attempt to update the
+ // monster grid (env.mgrid or mgrd for short). Since the hog is not
+ // stored in the monster list, this will corrupt the grid. The transit code
+ // will update the grid properly once the transiting hog has been placed.
+ if (!in_transit)
+ mon->move_to_pos(pos);
+ // "else {mon->position = pos}" is unnecessary because the transit code will
+ // ignore the old position anyway.
mon->enchantments = enchantments;
mon->hit_points = max(1, (int) (mon->max_hit_points * hp));
mon->flags = mon->flags | preserve_flags;