summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/delay.cc13
-rw-r--r--crawl-ref/source/delay.h4
-rw-r--r--crawl-ref/source/libutil.h27
-rw-r--r--crawl-ref/source/stash.cc5
-rw-r--r--crawl-ref/source/stash.h5
-rw-r--r--crawl-ref/source/travel.cc187
-rw-r--r--crawl-ref/source/travel.h33
7 files changed, 211 insertions, 63 deletions
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index 5f5879ac15..55ba0bb96c 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -909,12 +909,13 @@ inline static void monster_warning(activity_interrupt_type ai,
}
}
-void interrupt_activity( activity_interrupt_type ai,
+// Returns true if any activity was stopped.
+bool interrupt_activity( activity_interrupt_type ai,
const activity_interrupt_data &at )
{
const int delay = current_delay_action();
if (delay == DELAY_NOT_DELAYED)
- return;
+ return (false);
// First try to stop the current delay.
const delay_queue_item &item = you.delay_queue.front();
@@ -923,7 +924,7 @@ void interrupt_activity( activity_interrupt_type ai,
{
monster_warning(ai, at, item.type);
stop_delay();
- return;
+ return (true);
}
// Check the other queued delays; the first delay that is interruptible
@@ -943,16 +944,18 @@ void interrupt_activity( activity_interrupt_type ai,
{
monster_warning(ai, at, you.delay_queue[j].type);
stop_delay();
- return;
+ return (true);
}
}
// Non-run queued delays can be discarded without any processing.
you.delay_queue.erase( you.delay_queue.begin() + i,
you.delay_queue.end() );
- break;
+ return (true);
}
}
+
+ return (false);
}
static const char *activity_interrupt_names[] =
diff --git a/crawl-ref/source/delay.h b/crawl-ref/source/delay.h
index 778a14eeca..6e8f8196d7 100644
--- a/crawl-ref/source/delay.h
+++ b/crawl-ref/source/delay.h
@@ -28,8 +28,8 @@ const char *delay_name(int delay);
delay_type get_delay(const std::string &);
void perform_activity();
-void interrupt_activity( activity_interrupt_type ai,
- const activity_interrupt_data &a
+bool interrupt_activity( activity_interrupt_type ai,
+ const activity_interrupt_data &a
= activity_interrupt_data() );
#endif
diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h
index 0009f28882..e14c65d206 100644
--- a/crawl-ref/source/libutil.h
+++ b/crawl-ref/source/libutil.h
@@ -15,6 +15,7 @@
#include "AppHdr.h"
#include "defines.h"
+#include <cctype>
#include <string>
#include <vector>
@@ -67,6 +68,32 @@ std::vector<std::string> split_string(
bool trim = true,
bool accept_empties = false);
+inline std::string lowercase_first(std::string s)
+{
+ if (s.length())
+ s[0] = tolower(s[0]);
+ return (s);
+}
+
+template <class Z>
+std::string comma_separated_line(Z start, Z end)
+{
+ std::string text;
+ for (Z i = start; i != end; ++i)
+ {
+ if (i != start)
+ {
+ if (i + 1 != end)
+ text += ", ";
+ else
+ text += " and ";
+ }
+
+ text += i->name;
+ }
+ return (text);
+}
+
#ifdef NEED_USLEEP
void usleep( unsigned long time );
#endif
diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc
index ec1d189f44..4c295b27cb 100644
--- a/crawl-ref/source/stash.cc
+++ b/crawl-ref/source/stash.cc
@@ -1155,12 +1155,15 @@ LevelStashes &StashTracker::get_current_level()
LevelStashes *StashTracker::find_current_level()
{
+ if (is_level_untrackable())
+ return (NULL);
+
std::vector<LevelStashes>::iterator iter = levels.begin();
for ( ; iter != levels.end() && !iter->isBelowPlayer(); iter++)
{
if (iter->isCurrent()) return &*iter;
}
- return NULL;
+ return (NULL);
}
diff --git a/crawl-ref/source/stash.h b/crawl-ref/source/stash.h
index 58c6d3ce2a..e6bfd8ea5a 100644
--- a/crawl-ref/source/stash.h
+++ b/crawl-ref/source/stash.h
@@ -263,8 +263,9 @@ class StashTracker
public:
static bool is_level_untrackable()
{
- return you.level_type == LEVEL_LABYRINTH
- || you.level_type == LEVEL_ABYSS;
+ return you.level_type == LEVEL_LABYRINTH
+ || you.level_type == LEVEL_ABYSS
+ || you.level_type == LEVEL_PANDEMONIUM;
}
StashTracker() : levels()
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index 04ecd0b040..7fb1811965 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -15,6 +15,7 @@
#include "clua.h"
#include "delay.h"
#include "describe.h"
+#include "direct.h"
#include "itemname.h"
#include "items.h"
#include "misc.h"
@@ -252,6 +253,25 @@ static bool is_exclude_root(int x, int y)
return false;
}
+// Determines if the level is fully explored. Clobbers you.run_x/y.
+static bool fully_explored()
+{
+ const int oldrun = you.running;
+
+ if (!you.running.is_explore())
+ you.running = RMODE_EXPLORE;
+
+ // Do a second floodfill to check if the level is fully explored.
+ // Note we're passing in a features vector to force find_travel_pos to
+ // reseed past traps/deep water/lava. Icky.
+
+ std::vector<coord_def> features_dummy;
+ find_travel_pos(you.x_pos, you.y_pos, NULL, NULL, &features_dummy);
+ you.running = oldrun;
+
+ return !(you.running.x > 0 && you.running.y > 0);
+}
+
const char *run_mode_name(int runmode)
{
return runmode == RMODE_TRAVEL? "travel" :
@@ -704,58 +724,25 @@ bool prompt_stop_explore(int es_why)
|| yesno("Stop exploring?", true, 'n', true, false));
}
-static bool es_say(const char *what)
-{
- mprf("Found %s.", what);
- return (true);
-}
-
#define ES_item (Options.explore_stop & ES_ITEM)
-
-#define ES_shop ((Options.explore_stop & ES_SHOP) && \
- es_say("a shop") && prompt_stop_explore(ES_SHOP))
-
-#define ES_stair ((Options.explore_stop & ES_STAIR) && \
- es_say("a stair") && prompt_stop_explore(ES_STAIR))
-
-#define ES_altar ((Options.explore_stop & ES_ALTAR) && \
- es_say("an altar") && prompt_stop_explore(ES_ALTAR))
+#define ES_shop (Options.explore_stop & ES_SHOP)
+#define ES_stair (Options.explore_stop & ES_STAIR)
+#define ES_altar (Options.explore_stop & ES_ALTAR)
/*
- * Given a square that has just become visible during explore, returns true
- * if the player might consider the square worth stopping explore for.
+ * Adds interesting stuf on (x, y) to explore_discoveries.
*
* NOTE: These are env.map coords, add +1 to get grid coords.
*/
-static bool is_interesting_square(int x, int y)
+inline static void check_interesting_square(int x, int y,
+ explore_discoveries &ed)
{
- if (ES_item && igrd[x + 1][y + 1] != NON_ITEM)
- {
- bool valid_stop = true;
- if (you.running == RMODE_EXPLORE_GREEDY)
- {
- // The things we need to do...
- const LevelStashes *lev = stashes.find_current_level();
- if (lev && lev->needs_visit(x + 1, y + 1))
- valid_stop = false;
- }
-
- if (valid_stop)
- {
- mprf("Found %s.",
- item_name( mitm[ igrd[x + 1][y + 1] ], DESC_NOCAP_A ));
- if (prompt_stop_explore(ES_ITEM))
- return (true);
- }
- }
+ coord_def pos(x + 1, y + 1);
+
+ if (ES_item && igrd(pos) != NON_ITEM)
+ ed.found_item( pos, mitm[ igrd(pos) ] );
- unsigned char grid = grd[x + 1][y + 1];
- return (grid == DNGN_ENTER_SHOP && you.running != RMODE_EXPLORE_GREEDY
- && ES_shop)
- || (is_stair(grid) && ES_stair)
- || (is_altar(grid)
- && you.where_are_you != BRANCH_ECUMENICAL_TEMPLE
- && ES_altar);
+ ed.found_feature( pos, grd(pos) );
}
static void userdef_run_stoprunning_hook(void)
@@ -853,20 +840,23 @@ command_type travel()
// there are any squares of the shadow map that have just been
// discovered and contain an item, or have an interesting dungeon
// feature, stop exploring.
+
+ explore_discoveries discoveries;
for (int y = 0; y < GYM - 1; ++y)
{
for (int x = 0; x < GXM - 1; ++x)
{
if (!is_player_mapped(mapshadow[x][y])
- && is_player_mapped((unsigned char) env.map[x][y])
- && is_interesting_square(x, y))
+ && is_player_mapped((unsigned char) env.map[x][y]))
{
- stop_running();
- y = GYM;
- break;
+ check_interesting_square(x, y, discoveries);
}
}
}
+
+ if (discoveries.prompt_stop())
+ stop_running();
+
copy(env.map, mapshadow);
}
@@ -895,8 +885,12 @@ command_type travel()
// No place to go?
if (!you.running.x)
{
+ // Do fully_explored() *before* stop_running!
+ if (fully_explored())
+ mpr("Done exploring.");
+ else
+ mpr("Partly explored, some areas are inaccessible.");
stop_running();
- mpr("Done exploring.");
}
}
}
@@ -1080,12 +1074,13 @@ void find_travel_pos(int youx, int youy,
bool floodout = false;
unsigned char feature;
const LevelStashes *lev = stashes.find_current_level();
- const bool need_for_greed = you.running == RMODE_EXPLORE_GREEDY && can_autopickup();
+ const bool need_for_greed =
+ you.running == RMODE_EXPLORE_GREEDY && can_autopickup();
// For greedy explore, keep track of the closest unexplored
// territory and the closest greedy square.
- int e_x = 0, e_y = 0;
- int i_x = 0, i_y = 0;
+ int e_x = 0, e_y = 0; // Unexplored
+ int i_x = 0, i_y = 0; // Square with interesting item.
// Use these weird defaults to handle negative item greeds.
int ex_dist = -10000, ix_dist = -10000;
@@ -3356,3 +3351,89 @@ void runrest::check_mp()
stop();
}
}
+
+/////////////////////////////////////////////////////////////////////////////
+// explore_discoveries
+
+explore_discoveries::explore_discoveries()
+ : es_flags(0), current_level(NULL), items(), stairs(), shops(), altars()
+{
+}
+
+std::string explore_discoveries::cleaned_feature_description(int grid) const
+{
+ std::string s = lowercase_first(feature_description(grid));
+ if (s.length() && s[s.length() - 1] == '.')
+ {
+ s.erase(s.length() - 1);
+ }
+ return (s);
+}
+
+void explore_discoveries::found_feature(const coord_def &pos, int grid)
+{
+ if (grid == DNGN_ENTER_SHOP && ES_shop)
+ {
+ shops.push_back( named_thing<int>( shop_name(pos.x, pos.y), grid ) );
+ es_flags |= ES_SHOP;
+ }
+ else if (is_stair(grid) && ES_stair)
+ {
+ stairs.push_back(
+ named_thing<int>(
+ cleaned_feature_description(grid), grid ) );
+ es_flags |= ES_STAIR;
+ }
+ else if (is_altar(grid) && ES_altar)
+ {
+ altars.push_back(
+ named_thing<int>(
+ cleaned_feature_description(grid), grid ) );
+ es_flags |= ES_ALTAR;
+ }
+}
+
+void explore_discoveries::found_item(const coord_def &pos, const item_def &i)
+{
+ if (you.running == RMODE_EXPLORE_GREEDY)
+ {
+ // The things we need to do...
+ if (!current_level)
+ current_level = stashes.find_current_level();
+
+ if (current_level && current_level->needs_visit(pos.x, pos.y))
+ return;
+ }
+
+ items.push_back( named_thing<item_def>(item_name(i, DESC_NOCAP_A), i) );
+ es_flags |= ES_ITEM;
+}
+
+template <class C> void explore_discoveries::say_any(
+ const C &coll, const char *stub) const
+{
+ if (coll.empty())
+ return;
+
+ const std::string message = "Found " +
+ comma_separated_line(coll.begin(), coll.end()) + ".";
+
+ if ((int) message.length() >= get_number_of_cols())
+ mprf(stub, coll.size());
+ else
+ mprf("%s", message.c_str());
+}
+
+bool explore_discoveries::prompt_stop() const
+{
+ if (!es_flags)
+ return (false);
+
+ say_any(items, "Found %u items.");
+ say_any(stairs, "Found %u stairs.");
+ say_any(altars, "Found %u altars.");
+ say_any(shops, "Found %u shops.");
+
+ return ((Options.explore_stop_prompt & es_flags) != es_flags
+ || prompt_stop_explore(es_flags));
+}
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index 935840963c..a95948df2a 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -206,6 +206,39 @@ struct level_pos
void load(FILE *);
};
+// Tracks items discovered by explore in this turn.
+class LevelStashes;
+class explore_discoveries
+{
+public:
+ explore_discoveries();
+
+ void found_feature(const coord_def &pos, int grid);
+ void found_item(const coord_def &pos, const item_def &item);
+
+ // Reports discoveries and prompts the player to stop (if necessary).
+ bool prompt_stop() const;
+
+private:
+ template <class C> void say_any(const C &coll, const char *stub) const;
+ std::string cleaned_feature_description(int feature) const;
+
+private:
+ template <class Z> struct named_thing {
+ std::string name;
+ Z thing;
+
+ named_thing(const std::string &n, Z t) : name(n), thing(t) { }
+ };
+
+ int es_flags;
+ const LevelStashes *current_level;
+ std::vector< named_thing<item_def> > items;
+ std::vector< named_thing<int> > stairs;
+ std::vector< named_thing<int> > shops;
+ std::vector< named_thing<int> > altars;
+};
+
struct stair_info
{
coord_def position; // Position of stair