summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/docs/crawl_options.txt38
-rw-r--r--crawl-ref/source/acr.cc51
-rw-r--r--crawl-ref/source/debug.cc204
-rw-r--r--crawl-ref/source/debug.h3
-rw-r--r--crawl-ref/source/initfile.cc2
-rw-r--r--crawl-ref/source/invent.cc102
-rw-r--r--crawl-ref/source/invent.h5
-rw-r--r--crawl-ref/source/itemname.cc12
-rw-r--r--crawl-ref/source/luadgn.cc15
-rw-r--r--crawl-ref/source/luadgn.h1
-rw-r--r--crawl-ref/source/maps.cc11
-rw-r--r--crawl-ref/source/maps.h2
-rw-r--r--crawl-ref/source/message.cc33
-rw-r--r--crawl-ref/source/message.h8
-rw-r--r--crawl-ref/source/misc.cc5
-rw-r--r--crawl-ref/source/misc.h3
16 files changed, 437 insertions, 58 deletions
diff --git a/crawl-ref/docs/crawl_options.txt b/crawl-ref/docs/crawl_options.txt
index 8b86626a0f..a864b5ae48 100644
--- a/crawl-ref/docs/crawl_options.txt
+++ b/crawl-ref/docs/crawl_options.txt
@@ -784,18 +784,28 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order]
option as:
sort_menus = true : basename, qualname, curse, qty
+ Two items will be compared based on the first sort criteria
+ where they differ. So with the sort_menus line given above,
+ if the basenames of two different items are different they
+ will be alphabetically compared using their basenames; if
+ the basenames are the same but the qualified names different
+ it will compare their qualified names, and so on.
+
The available sort criteria are:
* basename:
This is the name of the item type. The basename for all of
"a +0 robe", "an embroidered robe" and "the cursed +2 robe
- of Ponies" is just "robe".
+ of Ponies" is just "robe". The basename for both of
+ "a brass ring" and "a ring of fire resistance" are "ring".
* qualname:
The name of the item without articles (a/an/the),
quantities, enchantments, or curse-status. The qualified
names for the robes described above are "robe", "embroidered
- robe" and "robe of Ponies", respectively.
+ robe" and "robe of Ponies", respectively. The qualified
+ names for the rings describe above are "brass ring" and
+ "ring of fire resistance", respectively.
* fullname:
This is the name of the item as displayed in menus
@@ -805,6 +815,18 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order]
Curse-status of the item (if known). Uncursed items show up
first.
+ * equipped:
+ Equipped items show up first.
+
+ * art:
+ Identified artefacts show up first.
+
+ * ego:
+ Identified ego items show up first.
+
+ * glowing:
+ Unidentified glowing/shiny/runed/etc items show up first.
+
* qty:
The quantity for stackable items (such as scrolls, potions,
etc.)
@@ -813,7 +835,17 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order]
The inventory letter for items in inventory; irrelevant for
items on the floor.
- The default sort criteria are: "basename, qualname, curse, qty".
+ * freshness:
+ The freshness of chunks of meat; irrelevant for everything
+ else. For non-ghouls it makes the freshest chunks of meat
+ show up first, and for ghouls the mons rotten chunks of
+ meat go fist. If this sort criteria is placed before (or
+ in the absence of) basename and qualname, then non-chunk
+ food items will be sorted between the non-rotting and
+ rotting chunks.
+
+ The default sort criteria are: "equipped, basename, qualname,
+ curse, qty".
You can ask for a descending order sort by prefixing one or
more sort criteria with > as:
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 4697d36360..f05e7d19d8 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -573,12 +573,12 @@ static void handle_wizard_command( void )
case 'd':
case 'D':
- level_travel(1);
+ level_travel(true);
break;
case 'u':
case 'U':
- level_travel(-1);
+ level_travel(false);
break;
case '%':
@@ -623,11 +623,11 @@ static void handle_wizard_command( void )
break;
case '>':
- grd[you.x_pos][you.y_pos] = DNGN_STONE_STAIRS_DOWN_I;
+ wizard_place_stairs(true);
break;
case '<':
- grd[you.x_pos][you.y_pos] = DNGN_ROCK_STAIRS_UP;
+ wizard_place_stairs(false);
break;
case 'p':
@@ -701,15 +701,46 @@ static void handle_wizard_command( void )
get_input_line(specs, sizeof specs);
if (*specs)
{
- const dungeon_feature_type feat = dungeon_feature_by_name(specs);
+ // Accept both "shallow_water" and "Shallow water"
+ std::string name = lowercase_string(specs);
+ name = replace_all(name, " ", "_");
+
+ dungeon_feature_type feat = dungeon_feature_by_name(name);
if (feat == DNGN_UNSEEN)
- canned_msg(MSG_OK);
- else
{
- mprf(MSGCH_DIAGNOSTICS, "Setting (%d,%d) to %s (%d)",
- you.x_pos, you.y_pos, specs, feat);
- grd(you.pos()) = feat;
+ std::vector<std::string> matches =
+ dungeon_feature_matches(name);
+
+ if (matches.empty())
+ {
+ mprf(MSGCH_DIAGNOSTICS, "No features matching '%s'",
+ name.c_str());
+ return;
+ }
+
+ // Only one possible match, use that.
+ if (matches.size() == 1)
+ {
+ name = matches[0];
+ feat = dungeon_feature_by_name(name);
+ }
+ // Multiple matches, list them to wizard
+ else
+ {
+ std::string prefix = "No exact match for feature '" +
+ name + "', possible matches are: ";
+
+ // Use mpr_comma_separated_list() because the list
+ // might be *LONG*.
+ mpr_comma_separated_list(prefix, matches, ", ", " and ",
+ MSGCH_DIAGNOSTICS);
+ return;
+ }
}
+
+ mprf(MSGCH_DIAGNOSTICS, "Setting (%d,%d) to %s (%d)",
+ you.x_pos, you.y_pos, name.c_str(), feat);
+ grd(you.pos()) = feat;
}
break;
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index abc6ec8c0f..9750100bae 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -414,6 +414,110 @@ void create_spec_monster_name(int x, int y)
}
#endif
+#ifdef WIZARD
+static dungeon_feature_type find_appropriate_stairs(bool down)
+{
+ if (you.level_type == LEVEL_DUNGEON)
+ {
+ int depth = subdungeon_depth(you.where_are_you, you.your_level);
+ if (down)
+ depth++;
+ else
+ depth--;
+
+ // Can't go down from bottom level of a branch.
+ if (depth > branches[you.where_are_you].depth)
+ {
+ mpr("Can't go down from the bottom of a branch.");
+ return DNGN_UNSEEN;
+ }
+ // Going up from top level of branch
+ else if (depth == 0)
+ {
+ // Special cases
+ if (you.where_are_you == BRANCH_VESTIBULE_OF_HELL)
+ return DNGN_EXIT_HELL;
+ else if (you.where_are_you == BRANCH_MAIN_DUNGEON)
+ return DNGN_STONE_STAIRS_UP_I;
+
+ // General case: look for branch exit and copy it
+ for (int y = 1; y < GYM; ++y)
+ {
+ for (int x = 1; x < GXM; ++x)
+ {
+ if (grd[x][y] >= DNGN_RETURN_FROM_ORCISH_MINES &&
+ grd[x][y] <= DNGN_RETURN_RESERVED_4)
+ return grd[x][y];
+ }
+ }
+
+ mpr("Unable to find appropriate branch exit.");
+ return DNGN_UNSEEN;
+ }
+ // Branch non-edge cases
+ else if (depth >= 1)
+ {
+ if (down)
+ return DNGN_STONE_STAIRS_DOWN_I;
+ else
+ return DNGN_ROCK_STAIRS_UP;
+ }
+ else
+ {
+ mpr("Bug in determing level exit.");
+ return DNGN_UNSEEN;
+ }
+ }
+
+ switch(you.level_type)
+ {
+ case LEVEL_LABYRINTH:
+ if (down)
+ {
+ // Can't go down in the Labyrinth
+ mpr("Can't go down in the Labyrinth.");
+ return DNGN_UNSEEN;
+ }
+ else
+ return DNGN_ROCK_STAIRS_UP;
+ break;
+
+ case LEVEL_ABYSS:
+ return DNGN_EXIT_ABYSS;
+ break;
+
+ case LEVEL_PANDEMONIUM:
+ if (down)
+ return DNGN_TRANSIT_PANDEMONIUM;
+ else
+ return DNGN_EXIT_PANDEMONIUM;
+ break;
+
+ case LEVEL_PORTAL_VAULT:
+ return DNGN_EXIT_PORTAL_VAULT;
+ break;
+
+ default:
+ mpr("Unknown level type.");
+ return DNGN_UNSEEN;
+ }
+
+ mpr("Impossible occurence in find_appropriate_stairs()");
+ return DNGN_UNSEEN;
+}
+#endif
+
+#ifdef WIZARD
+void wizard_place_stairs( bool down )
+{
+ dungeon_feature_type stairs = find_appropriate_stairs(down);
+
+ if (stairs == DNGN_UNSEEN)
+ return;
+
+ grd[you.x_pos][you.y_pos] = stairs;
+}
+#endif
//---------------------------------------------------------------
//
@@ -421,24 +525,24 @@ void create_spec_monster_name(int x, int y)
//
//---------------------------------------------------------------
#ifdef WIZARD
-void level_travel( int delta )
+void level_travel( bool down )
{
- int old_level = you.your_level;
- int new_level = you.your_level + delta;
-
- if (delta == 0)
- {
- new_level = debug_prompt_for_int( "Travel to which level? ", true ) - 1;
- }
+ dungeon_feature_type stairs = find_appropriate_stairs(down);
- if (new_level < 0 || new_level >= 50)
- {
- mpr( "That level is out of bounds." );
+ if (stairs == DNGN_UNSEEN)
return;
- }
- you.your_level = new_level - 1;
- down_stairs(old_level, DNGN_STONE_STAIRS_DOWN_I);
+ // This lets us, for example, use &U to exit from Pandemonium and
+ // &D to go to the next level.
+ command_type real_dir = grid_stair_direction(stairs);
+ if ((down && real_dir == CMD_GO_UPSTAIRS)
+ || (!down && real_dir == CMD_GO_DOWNSTAIRS))
+ down = !down;
+
+ if (down)
+ down_stairs(you.your_level, stairs);
+ else
+ up_stairs(stairs);
} // end level_travel()
static void wizard_go_to_level(const level_pos &pos)
@@ -487,26 +591,19 @@ void wizard_interlevel_travel()
void debug_list_monsters()
{
- std::string mons = "Monsters: ";
+ std::vector<std::string> mons;
int nfound = 0;
+
for (int i = 0; i < MAX_MONSTERS; ++i)
{
const monsters *m = &menv[i];
if (!m->alive())
continue;
- const std::string mname = m->name(DESC_PLAIN, true);
- std::string news = (nfound++? ", " : "") + mname;
- if (news.length() + mons.length() >= (unsigned) get_number_of_cols() - 1)
- {
- mpr(mons.c_str());
- mons.clear();
- news = mname;
- }
- mons += news;
+ mons.push_back(m->name(DESC_PLAIN, true));
+ nfound++;
}
- if (!mons.empty())
- mpr(mons.c_str());
+ mpr_comma_separated_list("Monsters: ", mons);
mprf("%d monsters", nfound);
}
@@ -2052,6 +2149,8 @@ void debug_make_trap()
return;
strlwr(requested_trap);
+ std::vector<int> matches;
+ std::vector<std::string> match_names;
for (int t = TRAP_DART; t < NUM_TRAPS; ++t)
{
if (strstr(requested_trap,
@@ -2060,12 +2159,32 @@ void debug_make_trap()
trap = trap_type(t);
break;
}
+ else if (strstr(trap_name(trap_type(t)), requested_trap))
+ {
+ matches.push_back(t);
+ match_names.push_back(trap_name(trap_type(t)));
+ }
}
if (trap == TRAP_UNASSIGNED)
{
- mprf("I know no traps named \"%s\"", requested_trap);
- return;
+ if (matches.empty())
+ {
+ mprf("I know no traps named \"%s\"", requested_trap);
+ return;
+ }
+ // Only one match, use that
+ else if (matches.size() == 1)
+ trap = trap_type(matches[0]);
+ else
+ {
+ std::string prefix = "No exact match for trap '";
+ prefix += requested_trap;
+ prefix += "', possible matches are: ";
+ mpr_comma_separated_list(prefix, match_names);
+
+ return;
+ }
}
place_specific_trap(you.x_pos, you.y_pos, trap);
@@ -2208,11 +2327,34 @@ void debug_set_xl()
static void debug_load_map_by_name(const std::string &name)
{
level_clear_vault_memory();
- const int map = find_map_by_name(name);
+ int map = find_map_by_name(name);
if (map == -1)
{
- mprf("Can't find map named '%s'.", name.c_str());
- return;
+ std::vector<std::string> matches = find_map_matches(name);
+
+ if (matches.empty())
+ {
+ mprf("Can't find map named '%s'.", name.c_str());
+ return;
+ }
+ else if (matches.size() == 1)
+ {
+ std::string prompt = "Only match is '";
+ prompt += matches[0];
+ prompt += "', use that?";
+ if (!yesno(prompt.c_str()))
+ return;
+
+ map = find_map_by_name(matches[0]);
+ }
+ else
+ {
+ std::string prompt = "No exact matches for '";
+ prompt += name;
+ prompt += "', possible matches are: ";
+ mpr_comma_separated_list(prompt, matches);
+ return;
+ }
}
if (dgn_place_map(map, false, true))
diff --git a/crawl-ref/source/debug.h b/crawl-ref/source/debug.h
index fc12ac434d..e3bdad8ed2 100644
--- a/crawl-ref/source/debug.h
+++ b/crawl-ref/source/debug.h
@@ -133,7 +133,8 @@ void error_message_to_player(void);
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void level_travel( int delta );
+void wizard_place_stairs( bool down );
+void level_travel( bool down );
void wizard_interlevel_travel();
// last updated 12may2000 {dlb}
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index 3f7f4493ac..dcf7c8d838 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -3001,5 +3001,5 @@ void menu_sort_condition::set_comparators(std::string &s)
{
init_item_sort_comparators(
cmp,
- s.empty()? "basename, qualname, curse, qty" : s);
+ s.empty()? "equipped, basename, qualname, curse, qty" : s);
}
diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc
index 057f4c8e7b..c1cc52102c 100644
--- a/crawl-ref/source/invent.cc
+++ b/crawl-ref/source/invent.cc
@@ -39,6 +39,7 @@
#include "stuff.h"
#include "view.h"
#include "menu.h"
+#include "randart.h"
///////////////////////////////////////////////////////////////////////////////
// Inventory menu shenanigans
@@ -108,6 +109,62 @@ const bool InvEntry::is_item_cursed() const
return (item_ident(*item, ISFLAG_KNOW_CURSE) && item_cursed(*item));
}
+const bool InvEntry::is_item_glowing() const
+{
+ return (!item_ident(*item, ISFLAG_KNOW_TYPE)
+ && (get_equip_desc(*item)
+ || (is_artefact(*item)
+ && (item->base_type == OBJ_WEAPONS
+ || item->base_type == OBJ_MISSILES
+ || item->base_type == OBJ_ARMOUR))));
+}
+
+const bool InvEntry::is_item_ego() const
+{
+ return (item_ident(*item, ISFLAG_KNOW_TYPE) && !is_artefact(*item)
+ && item->special != 0
+ && (item->base_type == OBJ_WEAPONS
+ || item->base_type == OBJ_MISSILES
+ || item->base_type == OBJ_ARMOUR));
+}
+
+const bool InvEntry::is_item_art() const
+{
+ return (item_ident(*item, ISFLAG_KNOW_TYPE) && is_artefact(*item));
+}
+
+const bool InvEntry::is_item_equipped() const
+{
+ if (item->link == -1 || item->x != -1 || item->y != -1)
+ return(false);
+
+ for (int i = 0; i < NUM_EQUIP; i++)
+ if (item->link == you.equip[i])
+ return (true);
+
+ return (false);
+}
+
+const int InvEntry::item_freshness() const
+{
+ if (item->base_type != OBJ_FOOD || item->sub_type != FOOD_CHUNK)
+ return 0;
+
+ int freshness = item->special - 100;
+
+ // Ensure that chunk freshness is never zero, since zero means
+ // that the item isn't a chunk.
+ if (freshness >= 0)
+ freshness++;
+
+ // Invert if not a ghoul, so that the freshest chunks will go
+ // at the top.
+ if (you.species != SP_GHOUL)
+ freshness *= -1;
+
+ return freshness;
+}
+
std::string InvEntry::get_text() const
{
std::ostringstream tstr;
@@ -323,11 +380,37 @@ int sort_item_slot(const InvEntry *a)
{
return a->item->link;
}
+
+int sort_item_freshness(const InvEntry *a)
+{
+ return a->item_freshness();
+}
+
bool sort_item_curse(const InvEntry *a)
{
return a->is_item_cursed();
}
+bool sort_item_glowing(const InvEntry *a)
+{
+ return !a->is_item_glowing();
+}
+
+bool sort_item_ego(const InvEntry *a)
+{
+ return !a->is_item_ego();
+}
+
+bool sort_item_art(const InvEntry *a)
+{
+ return !a->is_item_art();
+}
+
+bool sort_item_equipped(const InvEntry *a)
+{
+ return !a->is_item_equipped();
+}
+
static bool compare_invmenu_items(const InvEntry *a, const InvEntry *b,
const item_sort_comparators *cmps)
{
@@ -368,14 +451,19 @@ void init_item_sort_comparators(item_sort_comparators &list,
item_sort_fn cmp;
} cmp_map[] =
{
- { "basename", compare_item_str<sort_item_basename> },
- { "qualname", compare_item_str<sort_item_qualname> },
- { "fullname", compare_item_str<sort_item_fullname> },
- { "curse", compare_item<bool, sort_item_curse> },
- { "qty", compare_item<int, sort_item_qty> },
- { "slot", compare_item<int, sort_item_slot> },
+ { "basename", compare_item_str<sort_item_basename> },
+ { "qualname", compare_item_str<sort_item_qualname> },
+ { "fullname", compare_item_str<sort_item_fullname> },
+ { "curse", compare_item<bool, sort_item_curse> },
+ { "glowing", compare_item<bool, sort_item_glowing> },
+ { "ego", compare_item<bool, sort_item_ego> },
+ { "art", compare_item<bool, sort_item_art> },
+ { "equipped", compare_item<bool, sort_item_equipped> },
+ { "qty", compare_item<int, sort_item_qty> },
+ { "slot", compare_item<int, sort_item_slot> },
+ { "freshness", compare_item<int, sort_item_freshness> }
};
-
+
list.clear();
std::vector<std::string> cmps = split_string(",", set);
for (int i = 0, size = cmps.size(); i < size; ++i)
diff --git a/crawl-ref/source/invent.h b/crawl-ref/source/invent.h
index 4278fa222a..d9739b4793 100644
--- a/crawl-ref/source/invent.h
+++ b/crawl-ref/source/invent.h
@@ -71,6 +71,11 @@ public:
const std::string &get_qualname() const;
const std::string &get_fullname() const;
const bool is_item_cursed() const;
+ const bool is_item_glowing() const;
+ const bool is_item_ego() const;
+ const bool is_item_art() const;
+ const bool is_item_equipped() const;
+ const int item_freshness() const;
private:
void add_class_hotkeys(const item_def &i);
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index 2437217550..1237d50d04 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -1265,6 +1265,16 @@ std::string item_def::name_aux( description_level_type desc,
break;
case OBJ_JEWELLERY:
+ if (basename)
+ {
+ if ( jewellery_is_amulet(*this) )
+ buff << " amulet";
+ else // i.e., an amulet
+ buff << " ring";
+
+ break;
+ }
+
// not using {tried} here because there are some confusing
// issues to work out with how we want to handle jewellery
// artefacts and base type id. -- bwr
@@ -1282,7 +1292,7 @@ std::string item_def::name_aux( description_level_type desc,
}
}
- if (is_random_artefact( *this ) && !basename)
+ if (is_random_artefact( *this ))
{
buff << randart_jewellery_name(*this);
break;
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index e15cc68b7a..3430c0976b 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -874,6 +874,21 @@ dungeon_feature_type dungeon_feature_by_name(const std::string &name)
return (DNGN_UNSEEN);
}
+std::vector<std::string> dungeon_feature_matches(const std::string &name)
+{
+ std::vector<std::string> matches;
+
+ ASSERT(ARRAYSIZE(dngn_feature_names) == NUM_REAL_FEATURES);
+ if (name.empty())
+ return (matches);
+
+ for (unsigned i = 0; i < ARRAYSIZE(dngn_feature_names); ++i)
+ if (strstr(dngn_feature_names[i], name.c_str()))
+ matches.push_back(dngn_feature_names[i]);
+
+ return (matches);
+}
+
const char *dungeon_feature_name(dungeon_feature_type rfeat)
{
const unsigned feat = rfeat;
diff --git a/crawl-ref/source/luadgn.h b/crawl-ref/source/luadgn.h
index 04e85c2de0..071fb283e4 100644
--- a/crawl-ref/source/luadgn.h
+++ b/crawl-ref/source/luadgn.h
@@ -73,6 +73,7 @@ void dgn_reset_default_depth();
int dlua_stringtable(lua_State *ls, const std::vector<std::string> &s);
dungeon_feature_type dungeon_feature_by_name(const std::string &name);
+std::vector<std::string> dungeon_feature_matches(const std::string &name);
const char *dungeon_feature_name(dungeon_feature_type feat);
template <typename T>
diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc
index 859e6fe211..dbb8a4d501 100644
--- a/crawl-ref/source/maps.cc
+++ b/crawl-ref/source/maps.cc
@@ -316,6 +316,17 @@ int find_map_by_name(const std::string &name)
return (-1);
}
+std::vector<std::string> find_map_matches(const std::string &name)
+{
+ std::vector<std::string> matches;
+
+ for (unsigned i = 0, size = vdefs.size(); i < size; ++i)
+ if (vdefs[i].name.find(name) != std::string::npos)
+ matches.push_back(vdefs[i].name);
+ return (matches);
+}
+
+
// Returns a map for which PLACE: matches the given place.
int random_map_for_place(const level_id &place, bool want_minivault)
{
diff --git a/crawl-ref/source/maps.h b/crawl-ref/source/maps.h
index fd347f6a64..174349da58 100644
--- a/crawl-ref/source/maps.h
+++ b/crawl-ref/source/maps.h
@@ -49,6 +49,8 @@ int random_map_for_tag(const std::string &tag, bool want_minivault,
bool check_depth = false);
void add_parsed_map(const map_def &md);
+std::vector<std::string> find_map_matches(const std::string &name);
+
void read_maps();
void read_map(const std::string &file);
void run_map_preludes();
diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc
index ef34e89355..123533f1de 100644
--- a/crawl-ref/source/message.cc
+++ b/crawl-ref/source/message.cc
@@ -431,6 +431,39 @@ void mpr(const char *inf, msg_channel_type channel, int param)
}
}
+// mpr() an arbitrarily long list of strings without truncation or risk
+// of overflow.
+void mpr_comma_separated_list(const std::string prefix,
+ const std::vector<std::string> list,
+ const std::string &andc,
+ const std::string &comma,
+ const msg_channel_type channel,
+ const int param)
+{
+ std::string out = prefix;
+ unsigned width = get_number_of_cols() - 1;
+
+ for(int i = 0, size = list.size(); i < size; i++)
+ {
+ std::string new_str = list[i];
+
+ if (size > 0 && i < (size - 2))
+ new_str += comma;
+ else if (i == (size - 2))
+ new_str += andc;
+
+ if (out.length() + new_str.length() >= width)
+ {
+ mpr(out.c_str(), channel, param);
+ out = new_str;
+ }
+ else
+ out += new_str;
+ }
+ mpr(out.c_str(), channel, param);
+}
+
+
// checks whether a given message contains patterns relevant for
// notes, stop_running or sounds and handles these cases
static void mpr_check_patterns(const std::string& message,
diff --git a/crawl-ref/source/message.h b/crawl-ref/source/message.h
index c44a7fa3fe..92ad895d21 100644
--- a/crawl-ref/source/message.h
+++ b/crawl-ref/source/message.h
@@ -65,6 +65,14 @@ void formatted_mpr(const formatted_string& fs,
void formatted_message_history(const std::string &st,
msg_channel_type channel = MSGCH_PLAIN,
int param = 0);
+
+// mpr() an arbitrarily long list of strings
+void mpr_comma_separated_list(const std::string prefix,
+ const std::vector<std::string> list,
+ const std::string &andc = " and ",
+ const std::string &comma = ", ",
+ const msg_channel_type channel = MSGCH_PLAIN,
+ const int param = 0);
// 4.1-style mpr, currently named mprf for minimal disruption.
void mprf( msg_channel_type channel, int param, const char *format, ... );
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index d81bce85d5..ed29826c53 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1003,9 +1003,10 @@ static void leaving_level_now()
you.level_type_name = newtype;
}
-void up_stairs(void)
+void up_stairs(dungeon_feature_type force_stair)
{
- dungeon_feature_type stair_find = grd[you.x_pos][you.y_pos];
+ dungeon_feature_type stair_find =
+ force_stair? force_stair : grd[you.x_pos][you.y_pos];
const branch_type old_where = you.where_are_you;
const bool was_a_labyrinth = you.level_type != LEVEL_DUNGEON;
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index b31a248a71..c517b4c0d4 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -114,8 +114,7 @@ int trap_at_xy(int which_x, int which_y);
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void up_stairs(void);
-
+void up_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN);
// last updated 12may2000 {dlb}
/* ***********************************************************************