summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-03-18 07:05:07 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-03-18 07:05:07 +0000
commit3fdf3ab24ea63ecde6537ea122e2ab1cd6b8d4f1 (patch)
treea838b57e94a87f84fcdbf3e551b365aec922259d /crawl-ref/source
parentde11c27378236139089c48ecfb0b66457cc0d67c (diff)
downloadcrawl-ref-3fdf3ab24ea63ecde6537ea122e2ab1cd6b8d4f1.tar.gz
crawl-ref-3fdf3ab24ea63ecde6537ea122e2ab1cd6b8d4f1.zip
Banished uniques (including ghosts) will now be sent to the Abyss. Banished
non-uniques may also get the Abyss treatment if they clear a HD roll. Crawl tries very hard not to lose banished monsters, preserving them across Abyss shifts and teleports, and saving them on the transit list when the player escapes the Abyss. Breaks savefile compatibility. Toned down Vehumet and wizardry boosts a touch. Fixed bugginess where player could get aux unarmed attacks on a monster that just teleported away (by weapon of distortion). git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1052 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/abyss.cc63
-rw-r--r--crawl-ref/source/abyss.h1
-rw-r--r--crawl-ref/source/acr.cc3
-rw-r--r--crawl-ref/source/enum.h4
-rw-r--r--crawl-ref/source/externs.h9
-rw-r--r--crawl-ref/source/fight.cc11
-rw-r--r--crawl-ref/source/files.cc105
-rw-r--r--crawl-ref/source/items.cc4
-rw-r--r--crawl-ref/source/makefile.obj1
-rw-r--r--crawl-ref/source/misc.cc5
-rw-r--r--crawl-ref/source/mon-util.cc92
-rw-r--r--crawl-ref/source/monstuff.cc11
-rw-r--r--crawl-ref/source/mtransit.cc159
-rw-r--r--crawl-ref/source/mtransit.h39
-rw-r--r--crawl-ref/source/spells1.cc3
-rw-r--r--crawl-ref/source/spells4.cc2
-rw-r--r--crawl-ref/source/spl-cast.cc12
-rw-r--r--crawl-ref/source/tags.cc358
-rw-r--r--crawl-ref/source/travel.h9
19 files changed, 604 insertions, 287 deletions
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index ac82243fff..eb00207c74 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -21,6 +21,7 @@
#include "cloud.h"
#include "misc.h"
#include "monplace.h"
+#include "mtransit.h"
#include "dungeon.h"
#include "items.h"
#include "lev-pand.h"
@@ -190,35 +191,27 @@ static void generate_area(unsigned char gx1, unsigned char gy1,
}
}
+static void abyss_lose_monster(monsters &mons)
+{
+ if (mons.needs_transit())
+ mons.set_transit( level_id(LEVEL_ABYSS) );
+
+ mons.reset();
+}
void area_shift(void)
/*******************/
{
for (unsigned int i = 0; i < MAX_MONSTERS; i++)
{
- if (menv[i].type == -1)
- {
+ monsters &m = menv[i];
+
+ if (!m.alive())
continue;
- }
// remove non-nearby monsters
- if (menv[i].x < you.x_pos - 10
- || menv[i].x >= you.x_pos + 11
- || menv[i].y < you.y_pos - 10 || menv[i].y >= you.y_pos + 11)
- {
- menv[i].type = -1;
-
- mgrd[menv[i].x][menv[i].y] = NON_MONSTER;
-
- for (unsigned int j = 0; j < NUM_MONSTER_SLOTS; j++)
- {
- if (menv[i].inv[j] != NON_ITEM)
- {
- destroy_item( menv[i].inv[j] );
- menv[i].inv[j] = NON_ITEM;
- }
- }
- }
+ if (grid_distance(m.x, m.y, you.x_pos, you.y_pos) > 10)
+ abyss_lose_monster(m);
}
for (int i = 5; i < (GXM - 5); i++)
@@ -226,17 +219,17 @@ void area_shift(void)
for (int j = 5; j < (GYM - 5); j++)
{
// don't modify terrain by player
- if (i >= you.x_pos - 10 && i < you.x_pos + 11
- && j >= you.y_pos - 10 && j < you.y_pos + 11)
- {
+ if (grid_distance(i, j, you.x_pos, you.y_pos) <= 10)
continue;
- }
// nuke terrain otherwise
grd[i][j] = DNGN_UNSEEN;
// nuke items
destroy_item_stack( i, j );
+
+ if (mgrd[i][j] != NON_MONSTER)
+ abyss_lose_monster( menv[ mgrd[i][j] ] );
}
}
@@ -298,8 +291,20 @@ void area_shift(void)
mons_place( RANDOM_MONSTER, BEH_HOSTILE, MHITNOT, false, 1, 1,
LEVEL_ABYSS, PROX_AWAY_FROM_PLAYER ); // PROX_ANYWHERE?
}
+
+ // And allow monsters in transit another chance to return.
+ place_transiting_monsters();
}
+void save_abyss_uniques()
+{
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters &m = menv[i];
+ if (m.alive() && m.needs_transit())
+ m.set_transit( level_id(LEVEL_ABYSS) );
+ }
+}
void abyss_teleport( bool new_area )
/**********************************/
@@ -336,6 +341,12 @@ void abyss_teleport( bool new_area )
init_pandemonium(); // get new monsters
set_colours_from_monsters(); // and new colours
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ if (menv[i].alive())
+ abyss_lose_monster(menv[i]);
+ }
+
// Orbs and fixed artefacts are marked as "lost in the abyss"
for (k = 0; k < MAX_ITEMS; k++)
{
@@ -356,9 +367,6 @@ void abyss_teleport( bool new_area )
}
}
- for (i = 0; i < MAX_MONSTERS; i++)
- menv[i].type = -1;
-
for (i = 0; i < MAX_CLOUDS; i++)
delete_cloud( i );
@@ -384,4 +392,5 @@ void abyss_teleport( bool new_area )
if ( one_chance_in(5) )
grd[you.x_pos + 1][you.y_pos] = DNGN_ALTAR_LUCY;
+ place_transiting_monsters();
}
diff --git a/crawl-ref/source/abyss.h b/crawl-ref/source/abyss.h
index 9ecef56114..d25770473f 100644
--- a/crawl-ref/source/abyss.h
+++ b/crawl-ref/source/abyss.h
@@ -33,5 +33,6 @@ void area_shift(void);
* *********************************************************************** */
void abyss_teleport( bool new_area );
+void save_abyss_uniques();
#endif
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index f92c3747b3..a3a1bebe24 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -2981,8 +2981,7 @@ static void move_player(int move_x, int move_y)
ig2++;
}
- snprintf( info, INFO_SIZE, "Number of items present: %d", ig2 );
- mpr( info, MSGCH_DIAGNOSTICS );
+ mprf( MSGCH_DIAGNOSTICS, "Number of items present: %d", ig2 );
ig2 = 0;
for (igly = 0; igly < MAX_MONSTERS; igly++)
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index efce88b640..70b41f74d6 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -2374,8 +2374,9 @@ enum monster_flag_type
MF_SEEN = 0x40, // Player already seen monster
MF_DIVINE_PROTECTION = 0x80, // Monster has divine protection.
- MF_KNOWN_MIMIC = 0x100 // Mimic that has taken a swing at the PC,
+ MF_KNOWN_MIMIC = 0x100, // Mimic that has taken a swing at the PC,
// or that the player has inspected with ?
+ MF_BANISHED = 0x200 // Monster that has been banished.
};
enum mon_dam_level_type
@@ -3624,6 +3625,7 @@ enum tag_type // used during save/load process to identify data blocks
TAG_LEVEL_MONSTERS, // monsters
TAG_GHOST, // ghost
TAG_LEVEL_ATTITUDE, // monster attitudes
+ TAG_LOST_MONSTERS, // monsters in transit
NUM_TAGS
};
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index cd7002855c..e2083c1c3a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -816,6 +816,7 @@ struct mon_attack_def
};
class ghost_demon;
+class level_id;
class monsters : public actor
{
@@ -857,9 +858,17 @@ public:
std::auto_ptr<ghost_demon> ghost; // Ghost information.
public:
+ bool needs_transit() const;
+ void set_transit(level_id destination);
+ bool find_place_to_live(bool near_player = false);
+ bool find_place_near_player();
+ bool find_home_in(coord_def s, coord_def e);
+ bool find_home_anywhere();
+
void set_ghost(const ghost_demon &ghost);
void ghost_init();
void pandemon_init();
+ void destroy_inventory();
void reset();
void load_spells(int spellbook);
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 7b46f788d3..0d741668c5 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -495,6 +495,8 @@ bool melee_attack::player_attack()
if (cancel_attack)
return (false);
+ coord_def where = defender->pos();
+
if (player_hits_monster())
{
did_hit = true;
@@ -533,11 +535,14 @@ bool melee_attack::player_attack()
const bool did_primary_hit = did_hit;
- if (unarmed_ok && player_aux_unarmed())
+ if (unarmed_ok && where == defender->pos() && player_aux_unarmed())
return (true);
- if ((did_primary_hit || did_hit) && def->type != -1)
+ if ((did_primary_hit || did_hit) && def->alive()
+ && where == defender->pos())
+ {
print_wounds(def);
+ }
return (did_primary_hit || did_hit);
}
@@ -1691,7 +1696,7 @@ bool melee_attack::apply_damage_brand()
break;
}
- if (coinflip())
+ if (you.level_type != LEVEL_ABYSS && coinflip())
{
emit_nodmg_hit_message();
defender->banish();
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 5e73131373..3beb2d137e 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -68,6 +68,7 @@
#include "monstuff.h"
#include "mon-util.h"
#include "mstuff2.h"
+#include "mtransit.h"
#include "notes.h"
#include "player.h"
#include "randart.h"
@@ -540,14 +541,6 @@ bool travel_load_map( char branch, int absdepth )
return true;
}
-struct follower {
- monsters mons;
- std::vector<item_def> items;
-
- follower() : mons(), items() { }
- follower(const monsters &m) : mons(m), items() { }
-};
-
void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth,
char old_level, char where_were_you2 )
{
@@ -623,21 +616,8 @@ void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth,
#endif
follower f(*fmenv);
-
- for (int minvc = 0; minvc < NUM_MONSTER_SLOTS; ++minvc)
- {
- const int item = fmenv->inv[minvc];
- if (item == NON_ITEM)
- {
- f.items.push_back(item_def());
- continue;
- }
-
- f.items.push_back(mitm[item]);
- destroy_item( item );
- }
-
followers.push_back(f);
+ fmenv->destroy_inventory();
monster_cleanup(fmenv);
}
} // end of grabbing followers
@@ -887,88 +867,22 @@ found_stair:
if (mgrd[you.x_pos][you.y_pos] != NON_MONSTER)
monster_teleport(&menv[mgrd[you.x_pos][you.y_pos]], true);
- int following = 0;
-
// actually "move" the followers if applicable
if ((you.level_type == LEVEL_DUNGEON
|| you.level_type == LEVEL_PANDEMONIUM)
&& load_mode == LOAD_ENTER_LEVEL)
{
- for (int ic = 0; ic < 2; ic++)
+ while (!followers.empty())
{
- for (count_x = you.x_pos - 6; count_x < you.x_pos + 7;
- count_x++)
- {
- for (count_y = you.y_pos - 6; count_y < you.y_pos + 7;
- count_y++)
- {
- if (ic == 0
- && ((count_x < you.x_pos - 1)
- || (count_x > you.x_pos + 1)
- || (count_y < you.y_pos - 1)
- || (count_y > you.y_pos + 1)))
- {
- continue;
- }
-
- if (count_x == you.x_pos && count_y == you.y_pos)
- continue;
-
- if (mgrd[count_x][count_y] != NON_MONSTER
- || grd[count_x][count_y] < DNGN_FLOOR)
- {
- continue;
- }
-
- while (menv[following].type != -1)
- {
- following++;
-
- if (following >= MAX_MONSTERS)
- goto out_of_foll;
- }
-
- if (followers.size())
- {
- follower f = followers.front();
- followers.erase(followers.begin());
-
- menv[following] = f.mons;
- menv[following].x = count_x;
- menv[following].y = count_y;
- menv[following].target_x = 0;
- menv[following].target_y = 0;
- menv[following].flags |= MF_JUST_SUMMONED;
-
- for (int minvc = 0; minvc < NUM_MONSTER_SLOTS; minvc++)
- {
- menv[following].inv[minvc] = NON_ITEM;
-
- const item_def &minvitem = f.items[minvc];
- if (minvitem.base_type != OBJ_UNASSIGNED)
- {
- int itmf = get_item_slot(0);
- if (itmf == NON_ITEM)
- {
- menv[following].inv[minvc] = NON_ITEM;
- continue;
- }
-
- mitm[itmf] = minvitem;
- mitm[itmf].x = 0;
- mitm[itmf].y = 0;
- mitm[itmf].link = NON_ITEM;
- menv[following].inv[minvc] = itmf;
- }
- }
- mgrd[count_x][count_y] = following;
- } // followers.size()
- }
- }
+ follower f = followers.front();
+ followers.erase(followers.begin());
+ f.place(true);
}
} // end of moving followers
- out_of_foll:
+ // Load monsters in transit.
+ place_transiting_monsters();
+
redraw_all();
// Sanity forcing of monster inventory items (required?)
@@ -1253,7 +1167,6 @@ void load_ghost(void)
}
}
-
void restore_game(void)
{
std::string charFile = get_savedir_filename(you.your_name, "", "sav");
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 98a2c732e2..eb62d1fc99 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -2182,12 +2182,16 @@ static void update_enchantments( struct monsters *mon, int levels )
case ENCH_ABJ_VI:
if (remove_enchant_levels( mon, i, ENCH_ABJ_I, levels ))
{
+ // Re-add ABJ_I so that monster_die doesn't try to send the
+ // monster to the Abyss on KILL_RESET.
+ mons_add_ench( mon, ENCH_ABJ_I );
monster_die( mon, KILL_RESET, 0 );
}
break;
case ENCH_SHORT_LIVED:
+ mons_add_ench( mon, ENCH_ABJ_I );
monster_die( mon, KILL_RESET, 0 );
break;
diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj
index c192363222..a1bea5253a 100644
--- a/crawl-ref/source/makefile.obj
+++ b/crawl-ref/source/makefile.obj
@@ -45,6 +45,7 @@ monstuff.o \
monspeak.o \
mon-util.o \
mstuff2.o \
+mtransit.o \
mutation.o \
newgame.o \
notes.o \
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 19da6b667e..4dc7bc2544 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -35,6 +35,7 @@
#include "externs.h"
+#include "abyss.h"
#include "branch.h"
#include "cloud.h"
#include "delay.h"
@@ -834,6 +835,10 @@ void down_stairs( bool remove_stairs, int old_level, int force_stair )
if (collect_travel_data)
old_level_info.update();
+ // Preserve abyss uniques now, since this Abyss level will be deleted.
+ if (you.level_type == LEVEL_ABYSS)
+ save_abyss_uniques();
+
if (you.level_type == LEVEL_PANDEMONIUM
&& stair_find == DNGN_TRANSIT_PANDEMONIUM)
{
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 243b8f03e4..9b61ec053c 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -32,10 +32,12 @@
#include "debug.h"
#include "itemname.h"
#include "itemprop.h"
+#include "items.h"
#include "Kills.h"
#include "misc.h"
#include "monplace.h"
#include "mstuff2.h"
+#include "mtransit.h"
#include "player.h"
#include "randart.h"
#include "stuff.h"
@@ -2781,8 +2783,6 @@ void monsters::expose_to_element(beam_type, int)
void monsters::banish()
{
- // [dshaligram] FIXME: We should really put these monsters on a
- // queue and load them when the player enters the Abyss.
monster_die(this, KILL_RESET, 0);
}
@@ -3041,19 +3041,84 @@ void monsters::ghost_init()
inv.init(NON_ITEM);
enchantment.init(ENCH_NONE);
+ find_place_to_live();
+}
+
+bool monsters::find_home_in(coord_def s, coord_def e)
+{
+ for (int iy = s.y; iy <= e.y; ++iy)
+ {
+ for (int ix = s.x; ix <= e.x; ++ix)
+ {
+ if (!in_bounds(ix, iy))
+ continue;
+
+ if (ix == you.x_pos && iy == you.y_pos)
+ continue;
+
+ if (mgrd[ix][iy] != NON_MONSTER || grd[ix][iy] < DNGN_FLOOR)
+ continue;
+
+ x = ix;
+ y = iy;
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+bool monsters::find_place_near_player()
+{
+ return (find_home_in( you.pos() - coord_def(1, 1),
+ you.pos() + coord_def(1, 1) )
+ || find_home_in( you.pos() - coord_def(6, 6),
+ you.pos() + coord_def(6, 6) ));
+}
+
+bool monsters::find_home_anywhere()
+{
+ int tries = 600;
do
{
- x = random2(GXM - 20) + 10;
- y = random2(GYM - 20) + 10;
+ x = random_range(6, GXM - 7);
+ y = random_range(6, GYM - 7);
}
- while ((grd[x][y] != DNGN_FLOOR)
- || (mgrd[x][y] != NON_MONSTER));
+ while ((grd[x][y] != DNGN_FLOOR
+ || mgrd[x][y] != NON_MONSTER)
+ && tries-- > 0);
- mgrd[x][y] = monster_index(this);
+ return (tries >= 0);
+}
+
+bool monsters::find_place_to_live(bool near_player)
+{
+ if ((near_player && find_place_near_player())
+ || find_home_anywhere())
+ {
+ mgrd[x][y] = monster_index(this);
+ return (true);
+ }
+
+ return (false);
+}
+
+void monsters::destroy_inventory()
+{
+ for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ {
+ if (inv[j] != NON_ITEM)
+ {
+ destroy_item( inv[j] );
+ inv[j] = NON_ITEM;
+ }
+ }
}
void monsters::reset()
{
+ destroy_inventory();
+
enchantment.init(ENCH_NONE);
inv.init(NON_ITEM);
@@ -3076,6 +3141,19 @@ void monsters::reset()
ghost.reset(NULL);
}
+bool monsters::needs_transit() const
+{
+ return ((mons_is_unique(type)
+ || (flags & MF_BANISHED)
+ || (you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25)))
+ && !mons_has_ench(this, ENCH_ABJ_I, ENCH_ABJ_VI));
+}
+
+void monsters::set_transit(level_id dest)
+{
+ add_monster_to_transit(dest, *this);
+}
+
void monsters::load_spells(int book)
{
spells.init(MS_NO_SPELL);
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index bf34d15dc1..eb8c5915a4 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -338,6 +338,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
int monster_killed = monster_index(monster);
bool death_message =
!silent && mons_near(monster) && player_monster_visible(monster);
+ bool in_transit = false;
// From time to time Trog gives you a little bonus
if (killer == KILL_YOU && you.berserker)
@@ -660,6 +661,13 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
place_cloud( CLOUD_GREY_SMOKE_MON + random2(3), monster->x,
monster->y, 1 + random2(3) );
+ if (monster->needs_transit())
+ {
+ monster->flags |= MF_BANISHED;
+ monster->set_transit( level_id(LEVEL_ABYSS) );
+ in_transit = true;
+ }
+
// fall-through
case KILL_DISMISSED:
@@ -697,7 +705,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
random2avg(88, 3), 100, "a mummy death curse" );
}
}
- else if (monster->type == MONS_BORIS)
+ else if (monster->type == MONS_BORIS && !in_transit)
{
// XXX: actual blood curse effect for Boris? -- bwr
@@ -2091,6 +2099,7 @@ static bool handle_enchantment(struct monsters *monster)
if (monster->enchantment[p] < ENCH_ABJ_I)
{
+ monster->enchantment[p] = ENCH_ABJ_I;
monster_die(monster, KILL_RESET, 0);
died = true;
}
diff --git a/crawl-ref/source/mtransit.cc b/crawl-ref/source/mtransit.cc
new file mode 100644
index 0000000000..bb58f68909
--- /dev/null
+++ b/crawl-ref/source/mtransit.cc
@@ -0,0 +1,159 @@
+/*
+ * File: mtransit.cc
+ * Summary: Tracks monsters that are in suspended animation between levels.
+ * Written by: Darshan Shaligram
+ *
+ * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-03-15T20:10:20.648083Z $
+ */
+
+#include "AppHdr.h"
+
+#include "mtransit.h"
+#include "items.h"
+#include "mon-util.h"
+#include "stuff.h"
+
+#define MAX_LOST 100
+
+monsters_in_transit the_lost_ones;
+
+static void place_lost_monsters(m_transit_list &m);
+
+static void cull_lost(m_transit_list &mlist, int how_many)
+{
+ // First pass, drop non-uniques.
+ m_transit_list::iterator i = mlist.begin();
+
+ for ( ; i != mlist.end(); )
+ {
+ m_transit_list::iterator finger = i++;
+ if (!mons_is_unique(finger->mons.type))
+ {
+ mlist.erase(finger);
+
+ if (--how_many <= 0)
+ return;
+ }
+ }
+
+ // If we're still over the limit (unlikely), just lose
+ // the old ones.
+ while (how_many-- > MAX_LOST && !mlist.empty())
+ mlist.erase( mlist.begin() );
+}
+
+void add_monster_to_transit(level_id lid, const monsters &m)
+{
+ m_transit_list &mlist = the_lost_ones[lid];
+ mlist.push_back(m);
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Monster in transit: %s",
+ m.name(DESC_PLAIN).c_str());
+#endif
+
+ const int how_many = mlist.size();
+ if (how_many > MAX_LOST)
+ cull_lost(mlist, how_many);
+}
+
+void place_transiting_monsters()
+{
+ level_id c = level_id::current();
+
+ monsters_in_transit::iterator i = the_lost_ones.find(c);
+ if (i == the_lost_ones.end())
+ return;
+
+ place_lost_monsters(i->second);
+ if (i->second.empty())
+ the_lost_ones.erase(i);
+}
+
+static bool place_lost_monster(follower &f)
+{
+ return (f.place(false));
+}
+
+static void place_lost_monsters(m_transit_list &m)
+{
+ for (m_transit_list::iterator i = m.begin();
+ i != m.end(); )
+ {
+ m_transit_list::iterator mon = i++;
+
+ // Transiting monsters have a 50% chance of being placed.
+ if (coinflip())
+ continue;
+
+ if (place_lost_monster(*mon))
+ m.erase(mon);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// follower
+
+follower::follower(const monsters &m) : mons(m), items()
+{
+ load_mons_items();
+}
+
+void follower::load_mons_items()
+{
+ for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
+ if (mons.inv[i] != NON_ITEM)
+ items[i] = mitm[ mons.inv[i] ];
+ else
+ items[i].clear();
+}
+
+bool follower::place(bool near_player)
+{
+ for (int i = 0; i < MAX_MONSTERS - 5; ++i)
+ {
+ monsters &m = menv[i];
+ if (m.alive())
+ continue;
+
+ m = mons;
+ if (m.find_place_to_live(near_player))
+ {
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Placed follower: %s",
+ m.name(DESC_PLAIN).c_str());
+#endif
+ m.target_x = m.target_y = 0;
+ m.flags |= MF_JUST_SUMMONED;
+
+ restore_mons_items(m);
+ return (true);
+ }
+
+ m.reset();
+ break;
+ }
+
+ return (false);
+}
+
+void follower::restore_mons_items(monsters &m)
+{
+ for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
+ {
+ if (items[i].base_type == OBJ_UNASSIGNED)
+ m.inv[i] = NON_ITEM;
+ else
+ {
+ const int islot = get_item_slot(0);
+ m.inv[i] = islot;
+ if (islot == NON_ITEM)
+ continue;
+
+ item_def &it = mitm[islot];
+ it = items[i];
+ it.x = it.y = 0;
+ it.link = NON_ITEM;
+ }
+ }
+}
diff --git a/crawl-ref/source/mtransit.h b/crawl-ref/source/mtransit.h
new file mode 100644
index 0000000000..3ffc0adfc8
--- /dev/null
+++ b/crawl-ref/source/mtransit.h
@@ -0,0 +1,39 @@
+/*
+ * File: mtransit.h
+ * Summary: Tracking monsters in transit between levels.
+ * Written by: Darshan Shaligram
+ *
+ * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-03-15T20:10:20.648083Z $
+ */
+
+#ifndef MTRANSIT_H
+#define MTRANSIT_H
+
+#include "AppHdr.h"
+#include "travel.h"
+#include <map>
+#include <list>
+
+struct follower
+{
+ monsters mons;
+ FixedVector<item_def, NUM_MONSTER_SLOTS> items;
+
+ follower() : mons(), items() { }
+ follower(const monsters &m);
+ bool place(bool near_player = false);
+ void load_mons_items();
+ void restore_mons_items(monsters &m);
+};
+
+typedef std::list<follower> m_transit_list;
+typedef std::map<level_id, m_transit_list> monsters_in_transit;
+
+extern monsters_in_transit the_lost_ones;
+
+void add_monster_to_transit(level_id dest, const monsters &m);
+
+// Places (some of the) monsters eligible to be placed on this level.
+void place_transiting_monsters();
+
+#endif
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index 127f932915..ae7546c451 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -667,7 +667,10 @@ void abjuration(int pow)
abjLevel -= 1 + (random2(pow) / 8);
if (abjLevel < ENCH_ABJ_I)
+ {
+ mons_add_ench(monster, ENCH_ABJ_I);
monster_die(monster, KILL_RESET, 0);
+ }
else
{
simple_monster_message(monster, " shudders.");
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 17b6b4518a..341bc90502 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -1417,7 +1417,7 @@ static int distortion_monsters(int x, int y, int pow, int message)
}
else if (one_chance_in(3))
{
- monster_die(defender, KILL_RESET, 0);
+ defender->banish();
return 1;
}
else if (message)
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index ec0873abde..0eade5c58e 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -249,7 +249,7 @@ static int apply_vehumet_wizardry_boost(int spell, int chance)
{
int wizardry = player_mag_abil(false);
int fail_reduce = 100;
- int wiz_factor = 86;
+ int wiz_factor = 87;
if (you.religion == GOD_VEHUMET
&& you.duration[DUR_PRAYER]
@@ -258,8 +258,8 @@ static int apply_vehumet_wizardry_boost(int spell, int chance)
|| spell_typematch(spell, SPTYP_SUMMONING)))
{
// [dshaligram] Fail rate multiplier used to be .5, scaled
- // back to 60%.
- fail_reduce = fail_reduce * 60 / 100;
+ // back to 67%.
+ fail_reduce = fail_reduce * 67 / 100;
}
// [dshaligram] Apply wizardry factor here, rather than mixed into the
@@ -267,12 +267,12 @@ static int apply_vehumet_wizardry_boost(int spell, int chance)
while (wizardry-- > 0)
{
fail_reduce = fail_reduce * wiz_factor / 100;
- wiz_factor += (100 - wiz_factor) / 5;
+ wiz_factor += (100 - wiz_factor) / 3;
}
// Hard cap on fail rate reduction.
- if (fail_reduce < 40)
- fail_reduce = 40;
+ if (fail_reduce < 50)
+ fail_reduce = 50;
return (chance * fail_reduce / 100);
}
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 63fe4fc70b..ebf7587c2c 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -76,6 +76,7 @@
#include "itemprop.h"
#include "monstuff.h"
#include "mon-util.h"
+#include "mtransit.h"
#include "randart.h"
#include "skills.h"
#include "skills2.h"
@@ -99,9 +100,11 @@ FixedArray < bool, MAX_LEVELS, NUM_BRANCHES > tmp_file_pairs;
static void tag_construct_you(struct tagHeader &th);
static void tag_construct_you_items(struct tagHeader &th);
static void tag_construct_you_dungeon(struct tagHeader &th);
+static void tag_construct_lost_monsters(tagHeader &th);
static void tag_read_you(struct tagHeader &th, char minorVersion);
static void tag_read_you_items(struct tagHeader &th, char minorVersion);
static void tag_read_you_dungeon(struct tagHeader &th);
+static void tag_read_lost_monsters(tagHeader &th, int minorVersion);
static void tag_construct_level(struct tagHeader &th);
static void tag_construct_level_items(struct tagHeader &th);
@@ -118,6 +121,10 @@ static void tag_read_ghost(struct tagHeader &th, char minorVersion);
static void marshallGhost(tagHeader &th, const ghost_demon &ghost);
static ghost_demon unmarshallGhost( tagHeader &th );
+static void marshall_monster(tagHeader &th, const monsters &m);
+static void unmarshall_monster(tagHeader &th, monsters &m);
+static void marshall_item(tagHeader &th, const item_def &item);
+static void unmarshall_item(tagHeader &th, item_def &item);
// provide a wrapper for file writing, just in case.
int write2(FILE * file, const char *buffer, unsigned int count)
@@ -219,10 +226,11 @@ void marshallMap(struct tagHeader &th, const std::map<key,value>& data,
}
}
-void marshall_level_id( struct tagHeader& th, const level_id& id )
+void marshall_level_id( tagHeader& th, const level_id& id )
{
marshallByte(th, id.branch );
marshallLong(th, id.depth );
+ marshallByte(th, id.level_type);
}
void marshall_level_pos( struct tagHeader& th, const level_pos& lpos )
@@ -234,17 +242,15 @@ void marshall_level_pos( struct tagHeader& th, const level_pos& lpos )
template<typename key, typename value>
void unmarshallMap(struct tagHeader& th, std::map<key,value>& data,
- key (*key_unmarshall) (struct tagHeader&),
- value (*value_unmarshall)(struct tagHeader&) )
+ key (*key_unmarshall) (tagHeader&),
+ value (*value_unmarshall)(tagHeader&) )
{
long i, len = unmarshallLong(th);
key k;
- value v;
for ( i = 0; i < len; ++i )
{
k = key_unmarshall(th);
- v = value_unmarshall(th);
- data[k] = v;
+ data[k] = value_unmarshall(th);
}
}
@@ -254,12 +260,13 @@ T unmarshall_long_as( struct tagHeader& th )
return static_cast<T>(unmarshallLong(th));
}
-level_id unmarshall_level_id( struct tagHeader& th )
+level_id unmarshall_level_id( tagHeader& th )
{
level_id id;
id.branch = unmarshallByte(th);
id.depth = unmarshallLong(th);
- return id;
+ id.level_type = unmarshallByte(th);
+ return (id);
}
level_pos unmarshall_level_pos( struct tagHeader& th )
@@ -267,7 +274,7 @@ level_pos unmarshall_level_pos( struct tagHeader& th )
level_pos lpos;
lpos.pos.x = unmarshallLong(th);
lpos.pos.y = unmarshallLong(th);
- lpos.id = unmarshall_level_id(th);
+ lpos.id = unmarshall_level_id(th);
return lpos;
}
@@ -459,6 +466,9 @@ void tag_construct(struct tagHeader &th, int tagID)
case TAG_GHOST:
tag_construct_ghost(th);
break;
+ case TAG_LOST_MONSTERS:
+ tag_construct_lost_monsters(th);
+ break;
default:
// I don't know how to make that!
break;
@@ -557,6 +567,9 @@ int tag_read(FILE *fp, char minorVersion)
case TAG_GHOST:
tag_read_ghost(th, minorVersion);
break;
+ case TAG_LOST_MONSTERS:
+ tag_read_lost_monsters(th, minorVersion);
+ break;
default:
// I don't know how to read that!
return 0;
@@ -602,8 +615,11 @@ void tag_set_expected(char tags[], int fileType)
switch(fileType)
{
case TAGTYPE_PLAYER:
- if (i >= TAG_YOU && i <=TAG_YOU_DUNGEON)
+ if ((i >= TAG_YOU && i <=TAG_YOU_DUNGEON)
+ || i == TAG_LOST_MONSTERS)
+ {
tags[i] = 1;
+ }
break;
case TAGTYPE_PLAYER_NAME:
if (i == TAG_YOU)
@@ -910,6 +926,53 @@ static void tag_construct_you_dungeon(struct tagHeader &th)
marshall_level_pos, marshall_as_long<portal_type>);
}
+static void marshall_follower(tagHeader &th, const follower &f)
+{
+ marshall_monster(th, f.mons);
+ for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
+ marshall_item(th, f.items[i]);
+}
+
+static void unmarshall_follower(tagHeader &th, follower &f)
+{
+ unmarshall_monster(th, f.mons);
+ for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
+ unmarshall_item(th, f.items[i]);
+}
+
+static void marshall_follower_list(tagHeader &th, const m_transit_list &mlist)
+{
+ marshallShort( th, mlist.size() );
+
+ for (m_transit_list::const_iterator mi = mlist.begin();
+ mi != mlist.end(); ++mi)
+ {
+ marshall_follower( th, *mi );
+ }
+}
+
+static m_transit_list unmarshall_follower_list(tagHeader &th)
+{
+ m_transit_list mlist;
+
+ const int size = unmarshallShort(th);
+
+ for (int i = 0; i < size; ++i)
+ {
+ follower f;
+ unmarshall_follower(th, f);
+ mlist.push_back(f);
+ }
+
+ return (mlist);
+}
+
+static void tag_construct_lost_monsters(tagHeader &th)
+{
+ marshallMap( th, the_lost_ones, marshall_level_id,
+ marshall_follower_list );
+}
+
static void tag_read_you(struct tagHeader &th, char minorVersion)
{
char buff[20]; // For birth date
@@ -1200,7 +1263,8 @@ static void tag_read_you_dungeon(struct tagHeader &th)
}
unmarshallMap(th, stair_level,
- unmarshall_long_as<branch_type>, unmarshall_level_id);
+ unmarshall_long_as<branch_type>,
+ unmarshall_level_id);
unmarshallMap(th, shops_present,
unmarshall_level_pos, unmarshall_long_as<shop_type>);
unmarshallMap(th, altars_present,
@@ -1209,6 +1273,14 @@ static void tag_read_you_dungeon(struct tagHeader &th)
unmarshall_level_pos, unmarshall_long_as<portal_type>);
}
+static void tag_read_lost_monsters(tagHeader &th, int minorVersion)
+{
+ the_lost_ones.clear();
+
+ unmarshallMap(th, the_lost_ones,
+ unmarshall_level_id, unmarshall_follower_list);
+}
+
// ------------------------------- level tags ---------------------------- //
static void tag_construct_level(struct tagHeader &th)
@@ -1262,6 +1334,62 @@ static void tag_construct_level(struct tagHeader &th)
}
}
+static void marshall_item(tagHeader &th, const item_def &item)
+{
+ marshallByte(th, item.base_type);
+ marshallByte(th, item.sub_type);
+ marshallShort(th, item.plus);
+ marshallShort(th, item.plus2);
+ marshallLong(th, item.special);
+ marshallShort(th, item.quantity);
+
+ marshallByte(th, item.colour);
+ marshallShort(th, item.x);
+ marshallShort(th, item.y);
+ marshallLong(th, item.flags);
+
+ marshallShort(th, item.link); // unused
+ marshallShort(th, igrd[item.x][item.y]); // unused
+
+ marshallByte(th, item.slot);
+
+ marshallShort(th, item.orig_place);
+ marshallShort(th, item.orig_monnum);
+ marshallString(th, item.inscription.c_str(), 80);
+}
+
+static void unmarshall_item(tagHeader &th, item_def &item)
+{
+ item.base_type = (unsigned char) unmarshallByte(th);
+ item.sub_type = (unsigned char) unmarshallByte(th);
+ item.plus = unmarshallShort(th);
+ item.plus2 = unmarshallShort(th);
+ item.special = unmarshallLong(th);
+ item.quantity = unmarshallShort(th);
+ item.colour = (unsigned char) unmarshallByte(th);
+ item.x = unmarshallShort(th);
+ item.y = unmarshallShort(th);
+ item.flags = (unsigned long) unmarshallLong(th);
+
+ // [dshaligram] FIXME, remove this kludge when ARM_CAP is fully
+ // integrated.
+ if (item.base_type == OBJ_ARMOUR && item.sub_type == ARM_CAP)
+ item.sub_type = ARM_HELMET;
+
+ unmarshallShort(th); // mitm[].link -- unused
+ unmarshallShort(th); // igrd[item.x][item.y] -- unused
+
+ item.slot = unmarshallByte(th);
+ item.inscription.clear();
+
+ item.orig_place = unmarshallShort(th);
+ item.orig_monnum = unmarshallShort(th);
+
+ char insstring[80];
+ unmarshallString(th, insstring, 80);
+ item.inscription = std::string(insstring);
+}
+
static void tag_construct_level_items(struct tagHeader &th)
{
int i;
@@ -1278,37 +1406,53 @@ static void tag_construct_level_items(struct tagHeader &th)
// how many items?
marshallShort(th, MAX_ITEMS);
for (i = 0; i < MAX_ITEMS; ++i)
+ marshall_item(th, mitm[i]);
+}
+
+static void marshall_monster(tagHeader &th, const monsters &m)
+{
+ marshallByte(th, m.ac);
+ marshallByte(th, m.ev);
+ marshallByte(th, m.hit_dice);
+ marshallByte(th, m.speed);
+ marshallByte(th, m.speed_increment);
+ marshallByte(th, m.behaviour);
+ marshallByte(th, m.x);
+ marshallByte(th, m.y);
+ marshallByte(th, m.target_x);
+ marshallByte(th, m.target_y);
+ marshallLong(th, m.flags);
+
+ for (int j = 0; j < NUM_MON_ENCHANTS; j++)
+ marshallByte(th, m.enchantment[j]);
+
+ marshallShort(th, m.type);
+ marshallShort(th, m.hit_points);
+ marshallShort(th, m.max_hit_points);
+ marshallShort(th, m.number);
+ marshallShort(th, m.colour);
+
+ for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ marshallShort(th, m.inv[j]);
+
+ for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
+ marshallShort(th, m.spells[j]);
+
+ marshallByte(th, m.god);
+
+ if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON)
{
- marshallByte(th, mitm[i].base_type);
- marshallByte(th, mitm[i].sub_type);
- marshallShort(th, mitm[i].plus);
- marshallShort(th, mitm[i].plus2);
- marshallLong(th, mitm[i].special);
- marshallShort(th, mitm[i].quantity);
-
- marshallByte(th, mitm[i].colour);
- marshallShort(th, mitm[i].x);
- marshallShort(th, mitm[i].y);
- marshallLong(th, mitm[i].flags);
-
- marshallShort(th, mitm[i].link); // unused
- marshallShort(th, igrd[mitm[i].x][mitm[i].y]); // unused
-
- marshallByte(th, mitm[i].slot);
-
- marshallShort(th, mitm[i].orig_place);
- marshallShort(th, mitm[i].orig_monnum);
- marshallString(th, mitm[i].inscription.c_str(), 80);
+ // *Must* have ghost field set.
+ ASSERT(m.ghost.get());
+ marshallGhost(th, *m.ghost);
}
}
static void tag_construct_level_monsters(struct tagHeader &th)
{
- int i,j;
-
// how many mons_alloc?
marshallByte(th, 20);
- for (i = 0; i < 20; ++i)
+ for (int i = 0; i < 20; ++i)
marshallShort(th, env.mons_alloc[i]);
// how many monsters?
@@ -1318,46 +1462,8 @@ static void tag_construct_level_monsters(struct tagHeader &th)
// how many monster inventory slots?
marshallByte(th, NUM_MONSTER_SLOTS);
- for (i = 0; i < MAX_MONSTERS; i++)
- {
- const monsters &m = menv[i];
-
- marshallByte(th, m.ac);
- marshallByte(th, m.ev);
- marshallByte(th, m.hit_dice);
- marshallByte(th, m.speed);
- marshallByte(th, m.speed_increment);
- marshallByte(th, m.behaviour);
- marshallByte(th, m.x);
- marshallByte(th, m.y);
- marshallByte(th, m.target_x);
- marshallByte(th, m.target_y);
- marshallLong(th, m.flags);
-
- for (j = 0; j < NUM_MON_ENCHANTS; j++)
- marshallByte(th, m.enchantment[j]);
-
- marshallShort(th, m.type);
- marshallShort(th, m.hit_points);
- marshallShort(th, m.max_hit_points);
- marshallShort(th, m.number);
- marshallShort(th, m.colour);
-
- for (j = 0; j < NUM_MONSTER_SLOTS; j++)
- marshallShort(th, m.inv[j]);
-
- for (j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
- marshallShort(th, m.spells[j]);
-
- marshallByte(th, m.god);
-
- if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON)
- {
- // *Must* have ghost field set.
- ASSERT(m.ghost.get());
- marshallGhost(th, *m.ghost);
- }
- }
+ for (int i = 0; i < MAX_MONSTERS; i++)
+ marshall_monster(th, menv[i]);
}
void tag_construct_level_attitude(struct tagHeader &th)
@@ -1450,41 +1556,49 @@ static void tag_read_level_items(struct tagHeader &th, char minorVersion)
// how many items?
count = unmarshallShort(th);
for (i = 0; i < count; ++i)
- {
- mitm[i].base_type = (unsigned char) unmarshallByte(th);
- mitm[i].sub_type = (unsigned char) unmarshallByte(th);
- mitm[i].plus = unmarshallShort(th);
- mitm[i].plus2 = unmarshallShort(th);
- mitm[i].special = unmarshallLong(th);
- mitm[i].quantity = unmarshallShort(th);
- mitm[i].colour = (unsigned char) unmarshallByte(th);
- mitm[i].x = unmarshallShort(th);
- mitm[i].y = unmarshallShort(th);
- mitm[i].flags = (unsigned long) unmarshallLong(th);
-
- // [dshaligram] FIXME, remove this kludge when ARM_CAP is fully
- // integrated.
- if (mitm[i].base_type == OBJ_ARMOUR && mitm[i].sub_type == ARM_CAP)
- mitm[i].sub_type = ARM_HELMET;
-
- unmarshallShort(th); // mitm[].link -- unused
- unmarshallShort(th); // igrd[mitm[i].x][mitm[i].y] -- unused
-
- mitm[i].slot = unmarshallByte(th);
- mitm[i].inscription.clear();
+ unmarshall_item(th, mitm[i]);
+}
- mitm[i].orig_place = unmarshallShort(th);
- mitm[i].orig_monnum = unmarshallShort(th);
-
- char insstring[80];
- unmarshallString(th, insstring, 80);
- mitm[i].inscription = std::string(insstring);
- }
+static void unmarshall_monster(tagHeader &th, monsters &m)
+{
+ m.ac = unmarshallByte(th);
+ m.ev = unmarshallByte(th);
+ m.hit_dice = unmarshallByte(th);
+ m.speed = unmarshallByte(th);
+ // Avoid sign extension when loading files (Elethiomel's hang)
+ m.speed_increment = (unsigned char) unmarshallByte(th);
+ m.behaviour = unmarshallByte(th);
+ m.x = unmarshallByte(th);
+ m.y = unmarshallByte(th);
+ m.target_x = unmarshallByte(th);
+ m.target_y = unmarshallByte(th);
+ m.flags = unmarshallLong(th);
+
+ for (int j = 0; j < NUM_MON_ENCHANTS; j++)
+ m.enchantment[j] = unmarshallByte(th);
+
+ m.type = unmarshallShort(th);
+ m.hit_points = unmarshallShort(th);
+ m.max_hit_points = unmarshallShort(th);
+ m.number = unmarshallShort(th);
+
+ m.colour = unmarshallShort(th);
+
+ for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ m.inv[j] = unmarshallShort(th);
+
+ for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
+ m.spells[j] = unmarshallShort(th);
+
+ m.god = (god_type) unmarshallByte(th);
+
+ if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON)
+ m.set_ghost( unmarshallGhost(th) );
}
static void tag_read_level_monsters(struct tagHeader &th, char minorVersion)
{
- int i,j;
+ int i;
int count, ecount, icount;
// how many mons_alloc?
@@ -1502,41 +1616,7 @@ static void tag_read_level_monsters(struct tagHeader &th, char minorVersion)
for (i = 0; i < count; i++)
{
monsters &m = menv[i];
-
- m.ac = unmarshallByte(th);
- m.ev = unmarshallByte(th);
- m.hit_dice = unmarshallByte(th);
- m.speed = unmarshallByte(th);
- // Avoid sign extension when loading files (Elethiomel's hang)
- m.speed_increment = (unsigned char) unmarshallByte(th);
- m.behaviour = unmarshallByte(th);
- m.x = unmarshallByte(th);
- m.y = unmarshallByte(th);
- m.target_x = unmarshallByte(th);
- m.target_y = unmarshallByte(th);
- m.flags = unmarshallLong(th);
-
- for (j = 0; j < ecount; j++)
- m.enchantment[j] = unmarshallByte(th);
-
- m.type = unmarshallShort(th);
- m.hit_points = unmarshallShort(th);
- m.max_hit_points = unmarshallShort(th);
- m.number = unmarshallShort(th);
-
- m.colour = unmarshallShort(th);
-
- for (j = 0; j < icount; j++)
- m.inv[j] = unmarshallShort(th);
-
- for (j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
- m.spells[j] = unmarshallShort(th);
-
- m.god = (god_type) unmarshallByte(th);
-
- if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON)
- m.set_ghost( unmarshallGhost(th) );
-
+ unmarshall_monster(th, m);
// place monster
if (m.type != -1)
mgrd[m.x][m.y] = i;
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index c8bca8e0c6..1490f9df56 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -169,14 +169,15 @@ public:
bool operator == ( const level_id &id ) const
{
- return branch == id.branch && depth == id.depth
- && level_type == id.level_type;
+ return (level_type == LEVEL_DUNGEON?
+ branch == id.branch && depth == id.depth
+ && level_type == id.level_type
+ : level_type == id.level_type);
}
bool operator != ( const level_id &id ) const
{
- return branch != id.branch || depth != id.depth
- || level_type != id.level_type;
+ return !operator == (id);
}
bool operator <( const level_id &id ) const