diff options
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/acr.cc | 9 | ||||
-rw-r--r-- | crawl-ref/source/command.cc | 273 | ||||
-rw-r--r-- | crawl-ref/source/command.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/dat/descript/monsters.txt | 74 | ||||
-rw-r--r-- | crawl-ref/source/database.cc | 50 | ||||
-rw-r--r-- | crawl-ref/source/database.h | 6 | ||||
-rw-r--r-- | crawl-ref/source/describe.cc | 39 |
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 ®ex, + 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 ®ex) +std::vector<std::string> getLongDescKeysByRegex(const std::string ®ex) { if (!descriptionDB) { @@ -436,6 +473,17 @@ std::vector<std::string> getLongDescriptionByRegex(const std::string ®ex) return database_find_keys(descriptionDB, regex, true); } +std::vector<std::string> getLongDescBodiesByRegex(const std::string ®ex) +{ + 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 ®ex, bool ignore_case = false); +std::vector<std::string> database_find_bodies(DBM *database, + const std::string ®ex, + bool ignore_case = false); std::string getLongDescription(const std::string &key); -std::vector<std::string> getLongDescriptionByRegex(const std::string ®ex); +std::vector<std::string> getLongDescKeysByRegex(const std::string ®ex); +std::vector<std::string> getLongDescBodiesByRegex(const std::string ®ex); 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 )) |