summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mtransit.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/mtransit.cc')
-rw-r--r--crawl-ref/source/mtransit.cc159
1 files changed, 159 insertions, 0 deletions
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;
+ }
+ }
+}