filters out matches if they aren't of the desired type.
If there's more than one match, after selecting a match to look at, exiting from the description will return you to the menu, rather than to the dungeon.
If you've asked for monsters, you can toggle sorting of the menu between alphabetical and by aproximated monster toughness (this probably still needs some work, since it seems to say that ordinary worms are tougher than brain worms).
Only the monster symbol is coloured when showing a menu of monsters to describe.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2185 c06c8d41-db1a-0410-9941-cceddc491573
PAYI4UTJCR3XZSFOX5L35EURHRXQ6STO4Z7AQ3525QPNL3QYLNBAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
VRFQK6S2TXOFFO5K5HRDXPR7QEKKAZAVCASSIJVPWQ4GE26UOGTQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
KR655YT3I3U5DMN5NS3FPUGMDNT4BI56K3SFF2FNJ77C45NFKL5AC
ZIFFVCQ72K35WGIUMZYN3KOXIUXF2CNXWKG6ZWEZ6LT3NSF3XOQAC
Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
NXVPOFYKJFWQWKVPQUMWH2Y2KJEZX44BUOBFJ4JD4KFGPEGYHG4QC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
spell_type spell_by_name(const char* name)
{
if (name == NULL || strlen(name) == 0)
return (SPELL_NO_SPELL);
char spname[80];
for (int i = 0; i < NUM_SPELLS; i++)
{
spell_type type = static_cast<spell_type>(i);
strncpy( spname, spell_title(type), sizeof( spname ) );
if (strcasecmp(spname, name) == 0)
return (type);
}
return (SPELL_NO_SPELL);
}
spell_type spell_by_name(std::string name)
{
return spell_by_name(name.c_str());
}
if (strstr( strlwr(spname), strlwr(specs) ) != NULL)
{
if (your_spells(static_cast<spell_type>(i), 0, false)
== SPRET_ABORT)
{
crawl_state.cancel_cmd_repeat();
}
return;
}
spell_type type = spell_by_name(specs);
if (type == SPELL_NO_SPELL)
{
mpr((one_chance_in(20)) ? "Maybe you should go back to WIZARD school."
: "I couldn't find that spell.");
crawl_state.cancel_cmd_repeat();
return;
std::vector<std::string> getLongDescKeysByRegex(const std::string ®ex);
std::vector<std::string> getLongDescBodiesByRegex(const std::string ®ex);
std::vector<std::string> getLongDescKeysByRegex(const std::string ®ex,
db_find_filter filter = NULL);
std::vector<std::string> getLongDescBodiesByRegex(const std::string ®ex,
db_find_filter filter = NULL);
Menu desc_menu(MF_SINGLESELECT | MF_ANYPRINTABLE |
MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING);
int a = (int) entry_a->data;
int b = (int) entry_b->data;
if (a == b)
return false;
std::string a_name = mons_type_name(a, DESC_PLAIN);
std::string b_name = mons_type_name(b, DESC_PLAIN);
return ( lowercase(a_name) < lowercase(b_name));
}
// Compare monsters by level if there's a place where they both have a
// level defined, or by hitdice otherwise. If monsters are of equal
// toughness, compare names.
static bool compare_mon_toughness(MenuEntry *entry_a, MenuEntry* entry_b)
{
int a = (int) entry_a->data;
int b = (int) entry_b->data;
monster_type mon = get_monster_by_name(str, true);
if (mon < NUM_MONSTERS && mon != MONS_PROGRAM_BUG)
class DescMenu : public Menu
{
public:
DescMenu( int _flags, bool _show_mon )
: Menu(_flags), sort_alpha(true), showing_monsters(_show_mon)
{
set_highlighter(NULL);
set_prompt();
}
bool sort_alpha;
bool showing_monsters;
void set_prompt()
{
std::string prompt = "Describe which? ";
if (showing_monsters)
{
if (sort_alpha)
prompt += "(CTRL-S to sort by monster toughness)";
else
prompt += "(CTRL-S to sort by name)";
}
set_title(new MenuEntry(prompt, MEL_TITLE));
}
void sort()
me->colour = mon_en->colour;
if (me->colour == BLACK)
me->colour = LIGHTGREY;
str += " ('";
str += (char) mon_en->showchar;
str += "')";
if (sort_alpha)
std::sort(items.begin(), items.end(), compare_mon_names);
else
std::sort(items.begin(), items.end(), compare_mon_toughness);
for (unsigned int i = 0, size = items.size(); i < size; i++)
{
const char letter = index_to_letter(i);
std::vector<MenuEntry*> sel = desc_menu.show();
redraw_screen();
if ( sel.empty() )
{
list_commands_err = "Okay, then.";
return ("");
}
else
{
ASSERT(sel.size() == 1);
ASSERT(sel[0]->hotkeys.size() == 1);
return *((std::string*) sel[0]->data);
}
}
sort();
set_prompt();
}
};
return ("");
}
else if (mon_keys.size() > 52)
{
list_commands_err = "Too many monsters for symbol '";
list_commands_err += showchar;
list_commands_err += "'";
return ("");
}
std::sort(mon_keys.begin(), mon_keys.end());
return select_desc_key(mon_keys);
static bool monster_filter(std::string key, std::string body)
{
return (get_monster_by_name(key.c_str(), true) == MONS_PROGRAM_BUG);
mpr("Describe a monster, spell, or feature; regexs and partial names "
"are fine. Enter a single letter to list monsters displayed by "
"that symbol.");
mpr("Describe what? ");
char buf[80];
if (cancelable_get_line(buf, sizeof(buf)) || buf[0] == '\0')
{
list_commands_err = "Okay, then.";
return (false);
}
static bool feature_filter(std::string key, std::string body)
{
return (spell_by_name(key) != SPELL_NO_SPELL
|| get_monster_by_name(key.c_str(), true) != MONS_PROGRAM_BUG);
}
if (regex == "")
{
list_commands_err = "Description must contain at least one non-space.";
return (false);
}
// Try to get an exact match first.
std::string key;
std::string desc;
if (regex.size() == 1)
{
key = find_monster_key(regex[0]);
if (key == "")
return (false);
desc = getLongDescription(key);
}
else if (desc == "")
{
// Try to get an exact match first.
key = regex;
desc = getLongDescription(key);
key = find_description_key(regex);
if (key == "")
return (false);
desc = getLongDescription(key);
}
}
static bool find_description()
{
clrscr();
viewwindow(true, false);
mpr("Describe a (M)onster, (S)pell or (F)eature? ");
int ch = toupper(getch());
std::string type;
std::string extra;
db_find_filter filter;
switch(ch)
{
case 'M':
type = "monster";
extra = " Enter a single letter to list monsters displayed by "
"that symbol.";
filter = monster_filter;
break;
case 'S':
type = "spell";
filter = spell_filter;
break;
case 'F':
type = "feature";
filter = feature_filter;
break;
default:
list_commands_err = "Okay, then.";
return (false);
}
mprf("Describe a %s; partial names and regexs are fine.%s",
type.c_str(), extra.c_str());
mpr("Describe what? ");
char buf[80];
if (cancelable_get_line(buf, sizeof(buf)) || buf[0] == '\0')
{
list_commands_err = "Okay, then.";
return (false);
}
std::string regex = trimmed_string(buf);
if (regex == "")
{
list_commands_err = "Description must contain at least one non-space.";
return (false);
}
bool doing_mons = (ch == 'M');
bool by_mon_symbol = (doing_mons && regex.size() == 1);
// Try to get an exact match first.
if (!by_mon_symbol && !(*filter)(regex, ""))
{
// Try to get an exact match first.
std::string desc = getLongDescription(regex);
if (desc != "")
{
return do_description(regex);
}
}
std::vector<std::string> key_list;
if (by_mon_symbol)
key_list = get_monster_keys(regex[0]);
else
key_list = get_desc_keys(regex, filter);
if (key_list.size() == 0)
{
if (by_mon_symbol)
{
list_commands_err = "No monsters with symbol '";
list_commands_err += regex;
list_commands_err += "'";
}
else
{
list_commands_err = "No matching ";
list_commands_err += type;
list_commands_err += "s";
}
return (false);
}
else if (key_list.size() > 52)
{
if (by_mon_symbol)
{
list_commands_err = "Too many monsters with symbol '";
list_commands_err += regex;
list_commands_err += "' to display";
}
else
{
char num_buf[10];
sprintf(num_buf, "%d", key_list.size());
list_commands_err = "Too many matching ";
list_commands_err += type;
list_commands_err += "s (";
list_commands_err += num_buf;
list_commands_err += ") to display";
}
return (false);
}
else if (key_list.size() == 1)
{
return do_description(key_list[0]);
}
std::sort(key_list.begin(), key_list.end());
DescMenu desc_menu(MF_SINGLESELECT | MF_ANYPRINTABLE |
MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING,
doing_mons);
for (unsigned int i = 0, size = key_list.size(); i < size; i++)
{
const char letter = index_to_letter(i);
std::string str = uppercase_first(key_list[i]);
MenuEntry *me = new MenuEntry(uppercase_first(key_list[i]),
MEL_ITEM, 1, letter);
if (doing_mons)
{
monster_type mon = get_monster_by_name(str, true);
unsigned char colour = mons_class_colour(mon);
if (colour == BLACK)
colour = LIGHTGREY;
std::string prefix = "(<";
prefix += colour_to_str(colour);
prefix += ">";
prefix += (char) mons_char(mon);
prefix += "</";
prefix += colour_to_str(colour);
prefix += ">) ";
me->text = prefix + str;
me->data = (void*) mon;
}
else
me->data = (void*) &key_list[i];
desc_menu.add_entry(me);
}
desc_menu.sort();
while (true)
{
std::vector<MenuEntry*> sel = desc_menu.show();
redraw_screen();
if ( sel.empty() )
{
if (doing_mons && desc_menu.getkey() == CONTROL('S'))
desc_menu.toggle_sorting();
else
return (false);
}
else
{
ASSERT(sel.size() == 1);
ASSERT(sel[0]->hotkeys.size() == 1);
std::string key;
if (doing_mons)
key = mons_type_name((int) sel[0]->data, DESC_PLAIN);
else
key = *((std::string*) sel[0]->data);
if (do_description(key))
if ( getch() == 0 )
getch();
}
}
return (false);