summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/acr.cc9
-rw-r--r--crawl-ref/source/command.cc273
-rw-r--r--crawl-ref/source/command.h3
-rw-r--r--crawl-ref/source/dat/descript/monsters.txt74
-rw-r--r--crawl-ref/source/database.cc50
-rw-r--r--crawl-ref/source/database.h6
-rw-r--r--crawl-ref/source/describe.cc39
7 files changed, 370 insertions, 84 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 77d6fa8ed3..392cf51b65 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -438,8 +438,7 @@ static void handle_wizard_command( void )
switch (wiz_command)
{
case '?':
- list_commands(true); // tell it to list wizard commands
- redraw_screen();
+ list_commands(true, 0, true); // tell it to list wizard commands
break;
case CONTROL('G'):
@@ -1963,10 +1962,12 @@ void process_command( command_type cmd )
case CMD_DISPLAY_COMMANDS:
if (Options.tutorial_left)
+ {
list_tutorial_help();
+ redraw_screen();
+ }
else
- list_commands(false);
- redraw_screen();
+ list_commands(false, 0, true);
break;
case CMD_EXPERIENCE_CHECK:
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 26f55a4f0e..bb90b0423c 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -36,6 +36,7 @@
#include "libutil.h"
#include "menu.h"
#include "message.h"
+#include "mon-util.h"
#include "ouch.h"
#include "player.h"
#include "spl-cast.h"
@@ -681,63 +682,253 @@ help_file help_files[] = {
{ NULL, 0, false }
};
-static void find_description()
+static std::string list_commands_err = "";
+
+static std::string select_desc_key(std::vector<std::string> keys)
+{
+ Menu desc_menu(MF_SINGLESELECT | MF_ANYPRINTABLE |
+ MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING);
+
+ desc_menu.set_title(new MenuEntry("Describe which?", MEL_TITLE));
+
+ desc_menu.set_highlighter(NULL);
+
+ for (unsigned int i = 0, size = keys.size(); i < size; i++)
+ {
+ const char letter = index_to_letter(i);
+ std::string str = uppercase_first(keys[i]);
+
+ MenuEntry *me = new MenuEntry(uppercase_first(keys[i]),
+ MEL_ITEM, 1, letter);
+
+ monster_type mon = get_monster_by_name(str, true);
+ if (mon < NUM_MONSTERS && mon != MONS_PROGRAM_BUG)
+ {
+ monsterentry *mon_en = get_monster_data(mon);
+
+ me->colour = mon_en->colour;
+ if (me->colour == BLACK)
+ me->colour = LIGHTGREY;
+ str += " ('";
+ str += (char) mon_en->showchar;
+ str += "')";
+
+ me->text = str;
+ }
+
+ me->data = (void*) &keys[i];
+
+ desc_menu.add_entry(me);
+ }
+
+ 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);
+ }
+}
+
+static std::string find_description_key(std::string regex)
+{
+ std::vector<std::string> key_matches = getLongDescKeysByRegex(regex);
+
+ if (key_matches.size() == 1)
+ return (key_matches[0]);
+ else if (key_matches.size() > 52)
+ {
+ list_commands_err = "Too many matches for '";
+ list_commands_err += regex + "'";
+ return ("");
+ }
+
+ std::vector<std::string> body_matches = getLongDescBodiesByRegex(regex);
+
+ if (key_matches.size() == 0 && body_matches.size() == 0)
+ {
+ list_commands_err = "No matches for '";
+ list_commands_err += regex + "'";
+ return ("");
+ }
+ else if (key_matches.size() == 0 && body_matches.size() == 1)
+ return (body_matches[0]);
+
+ // Merge key_matches and body_matches, discarding duplicates.
+ std::vector<std::string> tmp = key_matches;
+ tmp.insert(tmp.end(), body_matches.begin(), body_matches.end());
+ std::sort(tmp.begin(), tmp.end());
+ std::vector<std::string> all_matches;
+ for (unsigned int i = 0, size = tmp.size(); i < size; i++)
+ if (i == 0 || all_matches[all_matches.size() - 1] != tmp[i])
+ {
+ all_matches.push_back(tmp[i]);
+ }
+
+ if (all_matches.size() > 52)
+ {
+ list_commands_err = "Too many matches for '";
+ list_commands_err += regex + "'";
+ return ("");
+ }
+
+ return select_desc_key(all_matches);
+}
+
+static std::string find_monster_key(unsigned char showchar)
+{
+ std::vector<std::string> mon_keys;
+
+ for (int i = 0; i < NUM_MONSTERS; i++)
+ {
+ if (i == MONS_PROGRAM_BUG)
+ continue;
+
+ monsterentry *me = get_monster_data(i);
+
+ if (me == NULL || me->name == NULL || me->name[0] == '\0')
+ continue;
+
+ if (me->mc != i)
+ continue;
+
+ if (getLongDescription(me->name) == "")
+ continue;
+
+ if (me->showchar == showchar)
+ mon_keys.push_back(me->name);
+ }
+
+ if (mon_keys.size() == 0)
+ {
+ list_commands_err = "No monsters displayed with symbol '";
+ list_commands_err += showchar;
+ list_commands_err += "'";
+
+ 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 find_description()
{
clrscr();
viewwindow(true, false);
- mpr("Describe what? (can be a partial name or a regex) ");
+ 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')
{
- canned_msg( MSG_OK);
- return;
+ list_commands_err = "Okay, then.";
+ return (false);
}
std::string regex = trimmed_string(buf);
if (regex == "")
{
- mpr("Description must contain at least one non-space.");
- return;
+ list_commands_err = "Description must contain at least one non-space.";
+ return (false);
}
// Try to get an exact match first.
- std::string key = regex;
- std::string desc = getLongDescription(key);
+ std::string key;
+ std::string desc;
- if (desc == "")
+ if (regex.size() == 1)
{
- std::vector<std::string> matches = getLongDescriptionByRegex(regex);
+ key = find_monster_key(regex[0]);
- if (matches.size() == 0)
- {
- mprf("Nothing matches '%s'", buf);
- return;
- }
- else if (matches.size() > 1)
- {
- std::string prefix = "No exact match for '" +
- regex + "', possible matches are: ";
+ if (key == "")
+ return (false);
- // Use mpr_comma_separated_list() because the list
- // might be *LONG*.
- mpr_comma_separated_list(prefix, matches, " and ", ", ",
- MSGCH_PLAIN);
- return;
- }
- else
+ 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);
+ }
+
+ monster_type mon_num = get_monster_by_name(key, true);
+ if (mon_num < NUM_MONSTERS && mon_num != MONS_PROGRAM_BUG)
+ {
+ if (mons_genus(mon_num) == MONS_DRACONIAN)
{
- // Only one match, use that.
- key = matches[0];
- desc = getLongDescription(key);
+ monsters mon;
+
+ mon.type = mon_num;
+
+ switch (mon_num)
+ {
+ case MONS_BLACK_DRACONIAN:
+ case MONS_MOTTLED_DRACONIAN:
+ case MONS_YELLOW_DRACONIAN:
+ case MONS_GREEN_DRACONIAN:
+ case MONS_PURPLE_DRACONIAN:
+ case MONS_RED_DRACONIAN:
+ case MONS_WHITE_DRACONIAN:
+ case MONS_PALE_DRACONIAN:
+ mon.number = mon_num;
+ break;
+ default:
+ mon.number = 0;
+ break;
+ }
+
+ describe_monsters(mon);
+ return (false);
}
+
+ unsigned char symbol = get_monster_data(mon_num)->showchar;
+
+ std::string symbol_prefix = "__";
+ symbol_prefix += symbol;
+ symbol_prefix += "_prefix";
+ desc = getLongDescription(symbol_prefix) + desc;
+
+ std::string symbol_suffix = "__";
+ symbol_suffix += symbol;
+ symbol_suffix += "_suffix";
+ desc += getLongDescription(symbol_suffix);
}
+
key = uppercase_first(key);
key += "$$";
clrscr();
print_description(key + desc);
+
+ return (true);
}
static int keyhelp_keyfilter(int ch)
@@ -754,13 +945,11 @@ static int keyhelp_keyfilter(int ch)
break;
case '/':
- find_description();
-
- if ( getch() == 0 )
- getch();
+ if (find_description())
+ if ( getch() == 0 )
+ getch();
viewwindow(true, false);
-
return -1;
}
return ch;
@@ -913,11 +1102,15 @@ void show_interlevel_travel_depth_help()
show_specific_help( interlevel_travel_depth_help );
}
-void list_commands(bool wizard, int hotkey)
+void list_commands(bool wizard, int hotkey, bool do_redraw_screen)
{
if (wizard)
{
list_wizard_commands();
+
+ if (do_redraw_screen)
+ redraw_screen();
+
return;
}
@@ -1129,7 +1322,17 @@ void list_commands(bool wizard, int hotkey)
"stashes, and <w>Ctrl-E</w> to erase them.\n",
true, true, cmdhelp_textfilter);
+ list_commands_err = "";
show_keyhelp_menu(cols.formatted_lines(), true, false, hotkey);
+
+ if (do_redraw_screen)
+ {
+ clrscr();
+ redraw_screen();
+ }
+
+ if (list_commands_err != "")
+ mpr(list_commands_err.c_str());
}
void list_tutorial_help()
diff --git a/crawl-ref/source/command.h b/crawl-ref/source/command.h
index 174acce2f7..b64e4059d0 100644
--- a/crawl-ref/source/command.h
+++ b/crawl-ref/source/command.h
@@ -62,7 +62,8 @@ void show_levelmap_help();
void show_targeting_help();
void show_interlevel_travel_branch_help();
void show_interlevel_travel_depth_help();
-void list_commands(bool wizard, int hotkey = 0);
+void list_commands(bool wizard, int hotkey = 0,
+ bool do_redraw_screen = false);
void list_tutorial_help(void);
// Actually defined in acr.cc; we may want to move this to command.cc
diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt
index 4258190ae1..72c9b7126c 100644
--- a/crawl-ref/source/dat/descript/monsters.txt
+++ b/crawl-ref/source/dat/descript/monsters.txt
@@ -1,4 +1,21 @@
%%%%
+__N_suffix
+
+$"The insensible son of Pandu sank down till he reached the Naga kingdom.
+Nagas, furnished with fangs containing virulent venom, bit him by
+thousands. The vegetable poison, mingled in the blood of the son of the
+Wind god, was neutralised by the snake-poison. The serpents had bitten
+all over his frame, except his chest, the skin of which was so tough that
+their fangs could not penetrate it.
+"On regaining consciousness, the son of Kunti burst his bands and began
+to press the snakes down under the ground. A remnant fled for life, and
+going to their king Vasuki, represented, 'O king of snakes, a man drowned
+under the water, bound in chords of shrubs; probably he had drunk poison.
+For when he fell amongst us, he was insensible. But when we began to bite
+him, he regained his senses, and bursting his fetters, commenced laying
+at us. May it please Your Majesty to enquire who is.'"
+ -_The Mahabharata, Sambhava Parva, Section CXXVIII
+%%%%
&
You feel a lump in the pit of your stomach.
@@ -95,10 +112,22 @@ Gloorx Vloq
A shadowy figure clothed in profound darkness.
%%%%
+greater naga
+
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+It looks strong an agressive.
+%%%%
Green Death
A bloated form covered in oozing sores and exhaling clouds of lethal poison.
%%%%
+guardian naga
+
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+These nagas are often used as guardians by powerful creatures.
+%%%%
Harold
An evil human bounty hunter.
@@ -171,6 +200,10 @@ Orb Guardian
A huge and glowing purple creature, created by the Orb to defend itself.
%%%%
+pandemonium lord
+
+Powerful demons inhabitting the endless halls of Pandemonium, each is different, with its own set of strengths and weaknesses.
+%%%%
Pit Fiend
A huge winged fiend with incredibly tough skin.
@@ -894,7 +927,7 @@ stuck in its teeth.
%%%%
large skeleton
-A skeleton compelled to unlife by the exercise of necromancy.
+A large skeleton compelled to unlife by the exercise of necromancy.
%%%%
large zombie
@@ -978,21 +1011,18 @@ The embalmed and undead corpse of an ancient servant of darkness.
naga
A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+%%%%
+naga mage
-"The insensible son of Pandu sank down till he reached the Naga kingdom.
-Nagas, furnished with fangs containing virulent venom, bit him by
-thousands. The vegetable poison, mingled in the blood of the son of the
-Wind god, was neutralised by the snake-poison. The serpents had bitten
-all over his frame, except his chest, the skin of which was so tough that
-their fangs could not penetrate it.
-"On regaining consciousness, the son of Kunti burst his bands and began
-to press the snakes down under the ground. A remnant fled for life, and
-going to their king Vasuki, represented, 'O king of snakes, a man drowned
-under the water, bound in chords of shrubs; probably he had drunk poison.
-For when he fell amongst us, he was insensible. But when we began to bite
-him, he regained his senses, and bursting his fetters, commenced laying
-at us. May it please Your Majesty to enquire who is.'"
- -_The Mahabharata, Sambhava Parva, Section CXXVIII
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+An eldritch nimbus trails its motions.
+%%%%
+naga warrior
+
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+It bears scars of many past battles.
%%%%
necromancer
@@ -1246,6 +1276,14 @@ small snake
The lesser dungeon snake.
%%%%
+small skeleton
+
+A skeleton compelled to unlife by the exercise of necromancy.
+%%%%
+small zombie
+
+A corpse raised to undeath by necromancy.
+%%%%
smoke demon
A writhing cloud of smoke hanging in the air.
@@ -1318,7 +1356,7 @@ swamp worm
A large slimy worm, adept at swimming through the muck of this foul swamp.
%%%%
-tentacled monster
+tentacled monstrosity
A writhing mass of tentacles, all covered in putrid mucus.
%%%%
@@ -1462,7 +1500,3 @@ ynoxinul
A demon with shiny metallic scales.
%%%%
-zombie
-
-A corpse raised to undeath by necromancy.
-%%%%
diff --git a/crawl-ref/source/database.cc b/crawl-ref/source/database.cc
index 6de91c3a1e..86ae4b098c 100644
--- a/crawl-ref/source/database.cc
+++ b/crawl-ref/source/database.cc
@@ -165,6 +165,12 @@ std::vector<std::string> database_find_keys(DBM *database,
{
std::string key((const char *)dbKey.dptr, dbKey.dsize);
+ if (key.find("__") != std::string::npos)
+ {
+ dbKey = dbm_nextkey(database);
+ continue;
+ }
+
if (tpat.matches(key))
matches.push_back(key);
@@ -174,6 +180,37 @@ std::vector<std::string> database_find_keys(DBM *database,
return (matches);
}
+std::vector<std::string> database_find_bodies(DBM *database,
+ const std::string &regex,
+ bool ignore_case)
+{
+ text_pattern tpat(regex, ignore_case);
+ std::vector<std::string> matches;
+
+ datum dbKey = dbm_firstkey(database);
+
+ while (dbKey.dptr != NULL)
+ {
+ std::string key((const char *)dbKey.dptr, dbKey.dsize);
+
+ if (key.find("__") != std::string::npos)
+ {
+ dbKey = dbm_nextkey(database);
+ continue;
+ }
+
+ datum dbBody = dbm_fetch(database, dbKey);
+ std::string body((const char *)dbBody.dptr, dbBody.dsize);
+
+ if (tpat.matches(body))
+ matches.push_back(key);
+
+ dbKey = dbm_nextkey(database);
+ }
+
+ return (matches);
+}
+
///////////////////////////////////////////////////////////////////////////
// Internal DB utility functions
static void trim_right(std::string &s)
@@ -425,7 +462,7 @@ std::string getLongDescription(const std::string &key)
return std::string((const char *)result.dptr, result.dsize);
}
-std::vector<std::string> getLongDescriptionByRegex(const std::string &regex)
+std::vector<std::string> getLongDescKeysByRegex(const std::string &regex)
{
if (!descriptionDB)
{
@@ -436,6 +473,17 @@ std::vector<std::string> getLongDescriptionByRegex(const std::string &regex)
return database_find_keys(descriptionDB, regex, true);
}
+std::vector<std::string> getLongDescBodiesByRegex(const std::string &regex)
+{
+ if (!descriptionDB)
+ {
+ std::vector<std::string> empty;
+ return (empty);
+ }
+
+ return database_find_bodies(descriptionDB, regex, true);
+}
+
static std::vector<std::string> description_txt_paths()
{
std::vector<std::string> txt_file_names;
diff --git a/crawl-ref/source/database.h b/crawl-ref/source/database.h
index b30d8814e6..357ab62a9a 100644
--- a/crawl-ref/source/database.h
+++ b/crawl-ref/source/database.h
@@ -43,9 +43,13 @@ datum database_fetch(DBM *database, const std::string &key);
std::vector<std::string> database_find_keys(DBM *database,
const std::string &regex,
bool ignore_case = false);
+std::vector<std::string> database_find_bodies(DBM *database,
+ const std::string &regex,
+ bool ignore_case = false);
std::string getLongDescription(const std::string &key);
-std::vector<std::string> getLongDescriptionByRegex(const std::string &regex);
+std::vector<std::string> getLongDescKeysByRegex(const std::string &regex);
+std::vector<std::string> getLongDescBodiesByRegex(const std::string &regex);
std::string getShoutString(const std::string &monst,
const std::string &suffix = "");
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 8555459057..c0d50a87e9 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -3555,10 +3555,12 @@ static std::string describe_draconian(const monsters *mon)
description += "scaled humanoid with wings.";
if (subsp != MONS_DRACONIAN)
- description += " " + describe_draconian_colour(subsp);
+ if (describe_draconian_colour(subsp) != "")
+ description += " " + describe_draconian_colour(subsp);
if (subsp != mon->type)
- description += " " + describe_draconian_role(mon);
+ if (describe_draconian_role(mon) != "")
+ description += " " + describe_draconian_role(mon);
return (description);
}
@@ -3593,6 +3595,13 @@ void describe_monsters(monsters& mons)
// -peterb 4/14/07
description << getLongDescription(mons.name(DESC_PLAIN));
+ unsigned char symbol = get_monster_data(mons.type)->showchar;
+
+ std::string symbol_prefix = "__";
+ symbol_prefix += symbol;
+ symbol_prefix += "_prefix";
+ description << getLongDescription(symbol_prefix);
+
// Now that the player has examined it, he knows it's a mimic.
if (mons_is_mimic(mons.type))
mons.flags |= MF_KNOWN_MIMIC;
@@ -3632,26 +3641,6 @@ void describe_monsters(monsters& mons)
case MONS_NAGA_WARRIOR:
case MONS_GUARDIAN_NAGA:
case MONS_GREATER_NAGA:
- switch (mons.type)
- {
- case MONS_GUARDIAN_NAGA:
- description << getLongDescription("naga")
- << "$These nagas are often used as guardians "
- "by powerful creatures.$";
- break;
- case MONS_GREATER_NAGA:
- description << getLongDescription("naga")
- << "$It looks strong and aggressive.$";
- break;
- case MONS_NAGA_MAGE:
- description << getLongDescription("naga")
- << "$An eldritch nimbus trails its motions.$";
- break;
- case MONS_NAGA_WARRIOR:
- description << getLongDescription("naga")
- << "$It bears scars of many past battles.$";
- break;
- }
if (you.species == SP_NAGA)
description << "It is particularly attractive.";
else
@@ -3718,6 +3707,12 @@ void describe_monsters(monsters& mons)
break;
}
+ description << "\n";
+ std::string symbol_suffix = "__";
+ symbol_suffix += symbol;
+ symbol_suffix += "_suffix";
+ description << getLongDescription(symbol_suffix);
+
#if DEBUG_DIAGNOSTICS
if (mons_class_flag( mons.type, M_SPELLCASTER ))