diff options
author | ennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-02-12 05:05:43 +0000 |
---|---|---|
committer | ennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-02-12 05:05:43 +0000 |
commit | 76a5cc5049290770249b6661a2f4558b7fbb645e (patch) | |
tree | fa2131d2cef62d963d3c6c821c3ca230b541260f | |
parent | aa6dd78dceb8d09547021cd319aaaef053df1f4f (diff) | |
download | crawl-ref-76a5cc5049290770249b6661a2f4558b7fbb645e.tar.gz crawl-ref-76a5cc5049290770249b6661a2f4558b7fbb645e.zip |
Mousing over monsters, items, and features will now show their description in the message window. This inadvertantly fixes [2469950], where some lines would appear off screen.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9030 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r-- | crawl-ref/source/command.cc | 15 | ||||
-rw-r--r-- | crawl-ref/source/describe.cc | 269 | ||||
-rw-r--r-- | crawl-ref/source/describe.h | 155 | ||||
-rw-r--r-- | crawl-ref/source/directn.cc | 30 | ||||
-rw-r--r-- | crawl-ref/source/directn.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/tilereg.cc | 178 | ||||
-rw-r--r-- | crawl-ref/source/tilereg.h | 6 | ||||
-rw-r--r-- | crawl-ref/source/tilesdl.cc | 36 |
8 files changed, 468 insertions, 224 deletions
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index ae0c88f9a1..1dcd900e9f 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -1255,10 +1255,9 @@ static bool _append_books(std::string &desc, item_def &item, std::string key) static bool _do_description(std::string key, std::string type, std::string footer = "") { + describe_info inf; std::string desc = getLongDescription(key); - std::string quote = getQuoteString(key); - - std::string prefix, suffix; + inf.quote = getQuoteString(key); int width = std::min(80, get_number_of_cols()); @@ -1267,8 +1266,8 @@ static bool _do_description(std::string key, std::string type, { if (is_good_god(which_god)) { - suffix = "$$" + god_name(which_god) + " won't accept worship from " - "undead or evil beings."; + inf.suffix = "$$" + god_name(which_god) + + " won't accept worship from undead or evil beings."; } std::string help = get_god_powers(which_god); if (!help.empty()) @@ -1361,7 +1360,11 @@ static bool _do_description(std::string key, std::string type, key = uppercase_first(key); linebreak_string2(footer, width - 1); - print_description(desc, key, suffix, prefix, footer, quote); + + inf.footer = footer; + inf.title = key; + + print_description(inf); return (true); } diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index ba24dcbc12..44cac75279 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -79,7 +79,7 @@ static void _append_value( std::string & description, int valu, bool plussed ) description += value_str; } -static int _count_desc_lines(const std::string _desc, const int width) +int count_desc_lines(const std::string _desc, const int width) { std::string desc = get_linebreak_string(_desc, width); @@ -104,129 +104,30 @@ static int _count_desc_lines(const std::string _desc, const int width) // word and such. The character $ is interpreted as a CR. // //--------------------------------------------------------------- -void print_description(const std::string &d, const std::string title, - const std::string suffix, const std::string prefix, - const std::string footer, const std::string quote) -{ - const unsigned int lineWidth = get_number_of_cols() - 1; - const int height = get_number_of_lines(); - - std::string desc; - - if (title.empty()) - desc = d; - else - { - desc = title + "$$"; - desc += d; - } - - int num_lines = _count_desc_lines(desc, lineWidth) + 1; - const int suffix_lines = _count_desc_lines(suffix, lineWidth); - const int prefix_lines = _count_desc_lines(prefix, lineWidth); - const int footer_lines = _count_desc_lines(footer, lineWidth) - + (footer.empty() ? 0 : 1); - const int quote_lines = _count_desc_lines(quote, lineWidth); - - // Prefer the footer over the suffix. - if (num_lines + suffix_lines + footer_lines <= height) - { - desc = desc + suffix; - num_lines += suffix_lines; - } - - // Prefer the footer over the prefix. - if (num_lines + prefix_lines + footer_lines <= height) - { - desc = prefix + desc; - num_lines += prefix_lines; - } - - // Prefer the footer over the quote. - if (num_lines + footer_lines + quote_lines + 1 <= height) - { - if (!desc.empty()) - { - desc += "$"; - num_lines++; - } - desc = desc + quote; - num_lines += quote_lines; - } - - if (!footer.empty() && num_lines + footer_lines <= height) - { - const int bottom_line = std::min(std::max(24, num_lines + 2), - height - footer_lines + 1); - const int newlines = bottom_line - num_lines; - - if (newlines >= 0) - { - desc.append(newlines, '\n'); - desc = desc + footer; - } - } +void print_description(const std::string &body) +{ + describe_info inf; + inf.body << body; + print_description(inf); +} - std::string::size_type nextLine = std::string::npos; - unsigned int currentPos = 0; +class default_desc_proc +{ +public: + int width() { return get_number_of_cols() - 1; } + int height() { return get_number_of_lines(); } + void print(const std::string &str) { cprintf("%s", str.c_str()); } + void nextline() { cgotoxy(1, wherey() + 1); } +}; +void print_description(const describe_info &inf) +{ clrscr(); textcolor(LIGHTGREY); - while (currentPos < desc.length()) - { - if (currentPos != 0) - cgotoxy(1, wherey() + 1); - - // See if $ sign is within one lineWidth. - nextLine = desc.find('$', currentPos); - - if (nextLine >= currentPos && nextLine < currentPos + lineWidth) - { - cprintf("%s", - (desc.substr(currentPos, nextLine-currentPos)).c_str()); - currentPos = nextLine + 1; - continue; - } - - // Handle real line breaks. No substitutions necessary, just update - // the counts. - nextLine = desc.find('\n', currentPos); - if (nextLine >= currentPos && nextLine < currentPos + lineWidth) - { - cprintf("%s", - (desc.substr(currentPos, nextLine-currentPos)).c_str()); - currentPos = nextLine + 1; - continue; - } - - // No newline -- see if rest of string will fit. - if (currentPos + lineWidth >= desc.length()) - { - cprintf((desc.substr(currentPos)).c_str()); - return; - } - - - // Ok, try to truncate at space. - nextLine = desc.rfind(' ', currentPos + lineWidth); - - if (nextLine > 0) - { - cprintf((desc.substr(currentPos, nextLine - currentPos)).c_str()); - currentPos = nextLine + 1; - continue; - } - - // Oops. Just truncate. - nextLine = currentPos + lineWidth; - - nextLine = std::min(d.length(), nextLine); - - cprintf((desc.substr(currentPos, nextLine - currentPos)).c_str()); - currentPos = nextLine; - } + default_desc_proc proc; + process_description<default_desc_proc>(proc, inf); } const char* jewellery_base_ability_string(int subtype) @@ -1885,8 +1786,8 @@ std::string get_item_description( const item_def &item, bool verbose, std::string quote = getQuoteString(db_name); - if (_count_desc_lines(db_desc, lineWidth) - + _count_desc_lines(quote, lineWidth) <= height) + if (count_desc_lines(db_desc, lineWidth) + + count_desc_lines(quote, lineWidth) <= height) { if (!db_desc.empty()) db_desc += "$"; @@ -2107,7 +2008,7 @@ std::string get_item_description( const item_def &item, bool verbose, case OBJ_POTIONS: #ifdef DEBUG_BLOOD_POTIONS // List content of timer vector for blood potions. - if (is_blood_potion(item)) + if (!dump && is_blood_potion(item)) { item_def stack = static_cast<item_def>(item); CrawlHashTable &props = stack.props; @@ -2199,17 +2100,14 @@ static std::string _get_feature_description_wide(int feat) return std::string(); } -void describe_feature_wide(int x, int y) +void get_feature_desc(const coord_def &pos, describe_info &inf) { - const coord_def pos(x, y); const dungeon_feature_type feat = grd(pos); - std::string desc = feature_description(pos, false, DESC_CAP_A, false); - std::string db_name = - grd[x][y] == DNGN_ENTER_SHOP ? "A shop" : desc; + std::string db_name = grd(pos) == DNGN_ENTER_SHOP ? "A shop" : desc; std::string long_desc = getLongDescription(db_name); - desc += ".$$"; + inf.body << desc << ".$$"; // If we couldn't find a description in the database then see if // the feature's base name is different. @@ -2252,15 +2150,22 @@ void describe_feature_wide(int x, int y) db_name = key; } - desc += long_desc; + inf.body << long_desc; // For things which require logic if (!custom_desc) - desc += _get_feature_description_wide(grd[x][y]); + inf.body << _get_feature_description_wide(grd(pos)); - std::string quote = getQuoteString(db_name); + inf.quote = getQuoteString(db_name); +} + +void describe_feature_wide(int x, int y) +{ + const coord_def pos(x, y); - print_description(desc, "", "", "", "", quote); + describe_info inf; + get_feature_desc(pos, inf); + print_description(inf); mouse_control mc(MOUSE_MODE_MORE); @@ -2289,25 +2194,31 @@ void set_feature_desc_long(const std::string &raw_name, desc_table[raw_name] = desc; } +void get_item_desc(const item_def &item, describe_info &inf) +{ + inf.body << get_item_description(item, true, false, Options.tutorial_left); +} + // Returns true if spells can be shown to player. static bool _show_item_description(const item_def &item) { const unsigned int lineWidth = get_number_of_cols() - 1; const int height = get_number_of_lines(); - std::string description = get_item_description( item, 1, false, - Options.tutorial_left); + describe_info inf; + std::string desc = + get_item_description(item, true, false, Options.tutorial_left); - int num_lines = _count_desc_lines(description, lineWidth) + 1; + int num_lines = count_desc_lines(desc, lineWidth) + 1; // XXX: hack: Leave room for "Inscribe item?" and the blank line above // it by removing item quote. This should really be taken care of // by putting the quotes into a separate DB and treating them as // a suffix that can be ignored by print_description(). if (height - num_lines <= 2) - description = get_item_description( item, 1, false, true); + desc = get_item_description(item, 1, false, true); - print_description(description); + print_description(desc); if (Options.tutorial_left) tutorial_describe_item(item); @@ -2798,21 +2709,18 @@ static std::string _monster_stat_description(const monsters& mon) return result.str(); } -void describe_monsters(const monsters& mons) +void get_monster_desc(const monsters& mons, describe_info &inf) { // For undetected mimics describe mimicked item instead. if (mons_is_mimic(mons.type) && !(mons.flags & MF_KNOWN_MIMIC)) { item_def item; get_mimic_item(&mons, item); - describe_item(item); + get_item_desc(item, inf); return; } - std::ostringstream body; - std::string title, prefix, suffix, quote; - - title = mons.full_name(DESC_CAP_A, true); + inf.title = mons.full_name(DESC_CAP_A, true); std::string db_name = mons.base_name(DESC_DBNAME); if (mons_is_mimic(mons.type) && mons.type != MONS_GOLD_MIMIC) @@ -2820,8 +2728,8 @@ void describe_monsters(const monsters& mons) // Don't get description for player ghosts. if (mons.type != MONS_PLAYER_GHOST) - body << getLongDescription(db_name); - quote = getQuoteString(db_name); + inf.body << getLongDescription(db_name); + inf.quote = getQuoteString(db_name); std::string symbol; symbol += get_monster_data(mons.type)->showchar; @@ -2831,12 +2739,12 @@ void describe_monsters(const monsters& mons) std::string symbol_prefix = "__"; symbol_prefix += symbol; symbol_prefix += "_prefix"; - prefix = getLongDescription(symbol_prefix); + inf.prefix = getLongDescription(symbol_prefix); std::string quote2 = getQuoteString(symbol_prefix); - if (!quote.empty() && !quote2.empty()) - quote += "$"; - quote += quote2; + if (!inf.quote.empty() && !quote2.empty()) + inf.quote += "$"; + inf.quote += quote2; // Except for draconians and player ghosts, I have to admit I find the // following special descriptions rather pointless. I certainly can't @@ -2848,15 +2756,15 @@ void describe_monsters(const monsters& mons) if (player_can_smell()) { if (player_mutation_level(MUT_SAPROVOROUS) == 3) - body << "$It smells great!$"; + inf.body << "$It smells great!$"; else - body << "$It stinks.$"; + inf.body << "$It stinks.$"; } break; case MONS_SWAMP_DRAKE: if (player_can_smell()) - body << "$It smells horrible.$"; + inf.body << "$It smells horrible.$"; break; case MONS_NAGA: @@ -2865,26 +2773,26 @@ void describe_monsters(const monsters& mons) case MONS_GUARDIAN_NAGA: case MONS_GREATER_NAGA: if (you.species == SP_NAGA) - body << "$It is particularly attractive.$"; + inf.body << "$It is particularly attractive.$"; else - body << "$It is strange and repulsive.$"; + inf.body << "$It is strange and repulsive.$"; break; case MONS_VAMPIRE: case MONS_VAMPIRE_KNIGHT: case MONS_VAMPIRE_MAGE: if (you.is_undead == US_ALIVE) - body << "$It wants to drink your blood!$"; + inf.body << "$It wants to drink your blood!$"; break; case MONS_REAPER: if (you.is_undead == US_ALIVE) - body << "$It has come for your soul!$"; + inf.body << "$It has come for your soul!$"; break; case MONS_ELF: // These are only possible from polymorphing or shapeshifting. - body << "$This one is remarkably plain looking.$"; + inf.body << "$This one is remarkably plain looking.$"; break; case MONS_DRACONIAN: @@ -2904,24 +2812,24 @@ void describe_monsters(const monsters& mons) case MONS_DRACONIAN_MONK: case MONS_DRACONIAN_KNIGHT: { - body << "$" << _describe_draconian( &mons ); + inf.body << "$" << _describe_draconian( &mons ); break; } case MONS_PLAYER_GHOST: - body << "The apparition of " << get_ghost_description(mons) << ".$"; + inf.body << "The apparition of " << get_ghost_description(mons) << ".$"; break; case MONS_PANDEMONIUM_DEMON: - body << _describe_demon(mons); + inf.body << _describe_demon(mons); break; case MONS_URUG: if (player_can_smell()) - body << "$He smells terrible.$"; + inf.body << "$He smells terrible.$"; break; case MONS_PROGRAM_BUG: - body << "If this monster is a \"program bug\", then it's " + inf.body << "If this monster is a \"program bug\", then it's " "recommended that you save your game and reload. Please report " "monsters who masquerade as program bugs or run around the " "dungeon without a proper description to the authorities.$"; @@ -2935,19 +2843,19 @@ void describe_monsters(const monsters& mons) { std::string result = _monster_stat_description(mons); if (!result.empty()) - body << "$" << result; + inf.body << "$" << result; } if (!mons_can_use_stairs(&mons)) { - body << "$" << mons_pronoun(static_cast<monster_type>(mons.type), + inf.body << "$" << mons_pronoun(static_cast<monster_type>(mons.type), PRONOUN_CAP, true) << " is incapable of using stairs.$"; } if (mons_is_summoned(&mons)) { - body << "$" << "This monster has been summoned, and is thus only " + inf.body << "$" << "This monster has been summoned, and is thus only " "temporary. Killing it yields no experience, nutrition " "or items.$"; } @@ -2955,13 +2863,13 @@ void describe_monsters(const monsters& mons) std::string symbol_suffix = "__"; symbol_suffix += symbol; symbol_suffix += "_suffix"; - suffix += getLongDescription(symbol_suffix); - suffix += getLongDescription(symbol_suffix + "_examine"); + inf.suffix += getLongDescription(symbol_suffix); + inf.suffix += getLongDescription(symbol_suffix + "_examine"); quote2 = getQuoteString(symbol_suffix); - if (!quote.empty() && !quote2.empty()) - quote += "$"; - quote += quote2; + if (!inf.quote.empty() && !quote2.empty()) + inf.quote += "$"; + inf.quote += quote2; #if DEBUG_DIAGNOSTICS if (mons_class_flag( mons.type, M_SPELLCASTER )) @@ -2975,14 +2883,14 @@ void describe_monsters(const monsters& mons) { if (!found_spell) { - body << "$$Monster Spells:$"; + inf.body << "$$Monster Spells:$"; found_spell = true; } - body << " " << i << ": " - << spell_title(hspell_pass[i]) - << " (" << static_cast<int>(hspell_pass[i]) - << ")$"; + inf.body << " " << i << ": " + << spell_title(hspell_pass[i]) + << " (" << static_cast<int>(hspell_pass[i]) + << ")$"; } } } @@ -2994,19 +2902,26 @@ void describe_monsters(const monsters& mons) { if (!has_item) { - body << "$Monster Inventory:$"; + inf.body << "$Monster Inventory:$"; has_item = true; } - body << " " << i << ") " + inf.body << " " << i << ") " << mitm[mons.inv[i]].name(DESC_NOCAP_A, false, true); } } #endif +} - print_description(body.str(), title, suffix, prefix, "", quote); +void describe_monsters(const monsters& mons) +{ + describe_info inf; + get_monster_desc(mons, inf); + print_description(inf); mouse_control mc(MOUSE_MODE_MORE); + // TODO enne - this should really move into get_monster_desc + // and an additional tutorial string added to describe_info. if (Options.tutorial_left) tutorial_describe_monster(&mons); diff --git a/crawl-ref/source/describe.h b/crawl-ref/source/describe.h index ab661c919c..647816ab57 100644 --- a/crawl-ref/source/describe.h +++ b/crawl-ref/source/describe.h @@ -11,6 +11,7 @@ #define DESCRIBE_H #include <string> +#include <sstream> #include "externs.h" #include "enum.h" @@ -27,6 +28,16 @@ enum item_description_type NUM_IDESC }; +struct describe_info +{ + std::ostringstream body; + std::string title; + std::string prefix; + std::string suffix; + std::string footer; + std::string quote; +}; + void append_spells(std::string &desc, const item_def &item); // last updated 12may2000 {dlb} @@ -53,6 +64,7 @@ void describe_god( god_type which_god, bool give_title ); * called from: directn * *********************************************************************** */ void describe_feature_wide(int x, int y); +void get_feature_desc(const coord_def &gc, describe_info &inf); // last updated 24 Dec 2008 {mpc} /* *********************************************************************** @@ -64,8 +76,9 @@ void set_feature_desc_long(const std::string &raw_name, /* *********************************************************************** * called from: item_use - shopping * *********************************************************************** */ -void describe_item( item_def &item, bool allow_inscribe = false ); -void inscribe_item( item_def &item, bool proper_prompt ); +void describe_item(item_def &item, bool allow_inscribe = false); +void get_item_desc(const item_def &item, describe_info &inf); +void inscribe_item(item_def &item, bool proper_prompt); /* *********************************************************************** * called from: command @@ -79,6 +92,7 @@ void append_missile_info(std::string &description); * called from: command - direct * *********************************************************************** */ void describe_monsters(const monsters &mons); +void get_monster_desc(const monsters &item, describe_info &inf); // last updated 12 Jun 2008 {jpeg} /* *********************************************************************** @@ -96,11 +110,10 @@ std::string get_skill_description(int skill, bool need_title = false); void describe_skill(int skill); -void print_description(const std::string &d, const std::string title = "", - const std::string suffix = "", - const std::string prefix = "", - const std::string footer = "", - const std::string quote = ""); +void print_description(const std::string &desc); +void print_description(const describe_info &inf); + +template<class T> void process_description(T &proc, const describe_info &inf); std::string randart_auto_inscription( const item_def& item ); void add_autoinscription( item_def &item, std::string ainscrip); @@ -110,4 +123,132 @@ int str_to_trap(const std::string &s); extern const char* god_gain_power_messages[NUM_GODS][MAX_GOD_ABILITIES]; +int count_desc_lines(const std::string _desc, const int width); + +/* *********************************************************************** + * template implementations + * *********************************************************************** */ +// My kingdom for a closure. +template<class T> +inline void process_description(T &proc, const describe_info &inf) +{ + const unsigned int line_width = proc.width(); + const int height = proc.height(); + + std::string desc; + + if (inf.title.empty()) + desc = inf.body.str(); + else + { + desc = inf.title + "$$"; + desc += inf.body.str(); + } + + int num_lines = count_desc_lines(desc, line_width) + 1; + + const int suffix_lines = count_desc_lines(inf.suffix, line_width); + const int prefix_lines = count_desc_lines(inf.prefix, line_width); + const int footer_lines = count_desc_lines(inf.footer, line_width) + + (inf.footer.empty() ? 0 : 1); + const int quote_lines = count_desc_lines(inf.quote, line_width); + + // Prefer the footer over the suffix. + if (num_lines + suffix_lines + footer_lines <= height) + { + desc = desc + inf.suffix; + num_lines += suffix_lines; + } + + // Prefer the footer over the prefix. + if (num_lines + prefix_lines + footer_lines <= height) + { + desc = inf.prefix + desc; + num_lines += prefix_lines; + } + + // Prefer the footer over the quote. + if (num_lines + footer_lines + quote_lines + 1 <= height) + { + if (!desc.empty()) + { + desc += "$"; + num_lines++; + } + desc = desc + inf.quote; + num_lines += quote_lines; + } + + if (!inf.footer.empty() && num_lines + footer_lines <= height) + { + const int bottom_line = std::min(std::max(24, num_lines + 2), + height - footer_lines + 1); + const int newlines = bottom_line - num_lines; + + if (newlines >= 0) + { + desc.append(newlines, '\n'); + desc = desc + inf.footer; + } + } + + std::string::size_type nextLine = std::string::npos; + unsigned int currentPos = 0; + + while (currentPos < desc.length()) + { + if (currentPos != 0) + proc.nextline(); + + // See if $ sign is within one line_width. + nextLine = desc.find('$', currentPos); + + if (nextLine >= currentPos && nextLine < currentPos + line_width) + { + proc.print(desc.substr(currentPos, nextLine-currentPos)); + currentPos = nextLine + 1; + continue; + } + + // Handle real line breaks. No substitutions necessary, just update + // the counts. + nextLine = desc.find('\n', currentPos); + if (nextLine >= currentPos && nextLine < currentPos + line_width) + { + proc.print(desc.substr(currentPos, nextLine-currentPos)); + currentPos = nextLine + 1; + continue; + } + + // No newline -- see if rest of string will fit. + if (currentPos + line_width >= desc.length()) + { + proc.print(desc.substr(currentPos)); + return; + } + + + // Ok, try to truncate at space. + nextLine = desc.rfind(' ', currentPos + line_width); + + if (nextLine > 0) + { + proc.print(desc.substr(currentPos, nextLine - currentPos)); + currentPos = nextLine + 1; + continue; + } + + // Oops. Just truncate. + nextLine = currentPos + line_width; + + nextLine = std::min(inf.body.str().length(), nextLine); + + proc.print(desc.substr(currentPos, nextLine - currentPos)); + currentPos = nextLine; + } +} + + + + #endif diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index 3bfc704e25..4ba3d94528 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -1658,8 +1658,38 @@ void terse_describe_square(const coord_def &c, bool in_range) _describe_cell(c, in_range); } +void get_square_desc(const coord_def &c, describe_info &inf) +{ + // NOTE: Keep this function in sync with full_describe_square. + + // Don't give out information for things outside LOS + if (!see_grid(c.x, c.y)) + return; + + const int mid = mgrd(c); + const int oid = igrd(c); + + if (mid != NON_MONSTER && player_monster_visible(&menv[mid])) + { + // First priority: monsters. + get_monster_desc(menv[mid], inf); + } + else if (oid != NON_ITEM) + { + // Second priority: objects. + get_item_desc(mitm[oid], inf); + } + else + { + // Third priority: features. + get_feature_desc(c, inf); + } +} + void full_describe_square(const coord_def &c) { + // NOTE: Keep this function in sync with get_square_desc. + // Don't give out information for things outside LOS if (!see_grid(c.x, c.y)) return; diff --git a/crawl-ref/source/directn.h b/crawl-ref/source/directn.h index 381e130ac0..da0d972f1b 100644 --- a/crawl-ref/source/directn.h +++ b/crawl-ref/source/directn.h @@ -10,6 +10,7 @@ #ifndef DIRECT_H #define DIRECT_H +#include "describe.h" #include "externs.h" #include "enum.h" #include "libgui.h" @@ -176,6 +177,8 @@ std::string thing_do_grammar(description_level_type dtype, std::string get_terse_square_desc(const coord_def &gc); void terse_describe_square(const coord_def &c, bool in_range = true); void full_describe_square(const coord_def &c); +void get_square_desc(const coord_def &c, describe_info &inf); + void describe_floor(); std::string get_monster_desc(const monsters *mon, bool full_desc = true, diff --git a/crawl-ref/source/tilereg.cc b/crawl-ref/source/tilereg.cc index 65d2bf0972..b155533961 100644 --- a/crawl-ref/source/tilereg.cc +++ b/crawl-ref/source/tilereg.cc @@ -1052,6 +1052,114 @@ bool DungeonRegion::update_tip_text(std::string& tip) return true; } +class alt_desc_proc +{ +public: + alt_desc_proc(int _w, int _h) { w = _w; h = _h; } + + int width() { return w; } + int height() { return h; } + void nextline() + { + ostr << "\n"; + } + void print(const std::string &str) + { + ostr << str; + } + + static int count_newlines(const std::string &str) + { + int count = 0; + for (size_t i = 0; i < str.size(); i++) + { + if (str[i] == '\n') + count++; + } + return count; + } + + // Remove trailing newlines. + static void trim(std::string &str) + { + int idx = str.size(); + while (--idx >= 0) + { + if (str[idx] != '\n') + break; + } + str.resize(idx + 1); + } + + // rfind consecutive newlines and truncate. + static bool chop(std::string &str) + { + int loc = -1; + for (size_t i = 1; i < str.size(); i++) + { + if (str[i] == '\n' && str[i-1] == '\n') + loc = i; + } + + if (loc == -1) + return false; + + str.resize(loc); + return true; + } + + void get_string(std::string &str) + { + str = replace_all(ostr.str(), "\n\n\n\n", "\n\n"); + str = replace_all(str, "\n\n\n", "\n\n"); + + trim(str); + while (count_newlines(str) > h) + { + if (!chop(str)) + break; + } + } + +protected: + int w; + int h; + std::ostringstream ostr; +}; + +bool DungeonRegion::update_alt_text(std::string &alt) +{ + if (mouse_control::current_mode() != MOUSE_MODE_COMMAND) + return false; + + const coord_def &gc = m_cursor[CURSOR_MOUSE]; + + if (gc == NO_CURSOR) + return false; + if (!map_bounds(gc)) + return false; + + if (!see_grid(gc)) + return false; + + describe_info inf; + get_square_desc(gc, inf); + + alt_desc_proc proc(crawl_view.msgsz.x, crawl_view.msgsz.y); + process_description<alt_desc_proc>(proc, inf); + + proc.get_string(alt); + + // Suppress floor description + if (alt == "Floor.") + { + alt.clear(); + return false; + } + + return true; +} + void DungeonRegion::clear_text_tags(text_tag_type type) { m_tags[type].clear(); @@ -1192,8 +1300,7 @@ void InventoryRegion::render() else desc = you.inv[idx].name(DESC_INVENTORY_EQUIP); - m_tag_font->render_string(x, y, - desc.c_str(), + m_tag_font->render_string(x, y, desc.c_str(), min_pos, max_pos, WHITE, false, 200); } } @@ -1689,12 +1796,39 @@ bool InventoryRegion::update_tip_text(std::string& tip) { tip += "\n[Shift-L-Click] Drop (d)"; } - } return true; } +bool InventoryRegion::update_alt_text(std::string &alt) +{ + if (m_cursor == NO_CURSOR) + return false; + + unsigned int item_idx = cursor_index(); + if (item_idx >= m_items.size() || m_items[item_idx].empty()) + return false; + + int idx = m_items[item_idx].idx; + + const item_def *item; + if (m_items[item_idx].flag & TILEI_FLAG_FLOOR) + item = &mitm[idx]; + else + item = &you.inv[idx]; + + describe_info inf; + get_item_desc(*item, inf); + + alt_desc_proc proc(crawl_view.msgsz.x, crawl_view.msgsz.y); + process_description<alt_desc_proc>(proc, inf); + + proc.get_string(alt); + + return true; +} + MapRegion::MapRegion(int pixsz) : m_buf(NULL), m_dirty(true), @@ -2256,6 +2390,15 @@ void MessageRegion::render() unsigned char char_back = 0; unsigned char col_back = 0; + if (!m_overlay && !m_alt_text.empty()) + { + coord_def min_pos(sx, sy); + coord_def max_pos(ex, ey); + m_font->render_string(sx + ox, sy + oy, m_alt_text.c_str(), + min_pos, max_pos, WHITE, false); + return; + } + if (this == TextRegion::cursor_region && cursor_x > 0 && cursor_y > 0) { idx = cursor_x + mx * cursor_y; @@ -2289,34 +2432,13 @@ void MessageRegion::render() if (height > 0) { height *= m_font->char_height(); - box_vert verts[4]; - for (int i = 0; i < 4; i++) - { - verts[i].r = 100; - verts[i].g = 100; - verts[i].b = 100; - verts[i].a = 100; - } - verts[0].x = sx; - verts[0].y = sy; - verts[1].x = sx; - verts[1].y = sy + height; - verts[2].x = ex; - verts[2].y = sy + height; - verts[3].x = ex; - verts[3].y = sy; glLoadIdentity(); - GLState state; - state.array_vertex = true; - state.array_colour = true; - state.blend = true; - GLStateManager::set(state); - - glVertexPointer(2, GL_FLOAT, sizeof(box_vert), &verts[0].x); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(box_vert), &verts[0].r); - glDrawArrays(GL_QUADS, 0, sizeof(verts) / sizeof(box_vert)); + ShapeBuffer buff; + VColour col(100, 100, 100, 100); + buff.add(sx, sy, ex, sy + height, col); + buff.draw(); } } diff --git a/crawl-ref/source/tilereg.h b/crawl-ref/source/tilereg.h index 7bee88c983..b6f75de610 100644 --- a/crawl-ref/source/tilereg.h +++ b/crawl-ref/source/tilereg.h @@ -50,6 +50,7 @@ public: bool inside(int px, int py); virtual bool update_tip_text(std::string &tip) { return false; } + virtual bool update_alt_text(std::string &alt) { return false; } virtual int handle_mouse(MouseEvent &event) = 0; virtual void render() = 0; @@ -167,7 +168,10 @@ public: virtual int handle_mouse(MouseEvent &event); virtual void render(); virtual bool update_tip_text(std::string &tip); + + std::string &alt_text() { return m_alt_text; } protected: + std::string m_alt_text; bool m_overlay; }; @@ -256,6 +260,7 @@ public: virtual void clear(); virtual int handle_mouse(MouseEvent &event); virtual bool update_tip_text(std::string &tip); + virtual bool update_alt_text(std::string &alt); virtual void on_resize(); void load_dungeon(unsigned int* tileb, int cx_to_gx, int cy_to_gy); @@ -338,6 +343,7 @@ public: void update(int num, InventoryTile *items); void update_slot(int slot, InventoryTile &item); virtual bool update_tip_text(std::string &tip); + virtual bool update_alt_text(std::string &alt); protected: void pack_tile(int x, int y, int idx); diff --git a/crawl-ref/source/tilesdl.cc b/crawl-ref/source/tilesdl.cc index bf9f281ca3..06a8de6ee7 100644 --- a/crawl-ref/source/tilesdl.cc +++ b/crawl-ref/source/tilesdl.cc @@ -724,13 +724,33 @@ int TilesFramework::getch_ck() ticks = SDL_GetTicks(); if (event.type != SDL_USEREVENT) + { tiles.clear_text_tags(TAG_CELL_DESC); + m_region_msg->alt_text().clear(); + } + + // TODO enne - need to find a better time to decide when + // to generate a tip or some way to say "yes, but unchanged". + if (ticks > m_last_tick_moved) + { + m_region_msg->alt_text().clear(); + for (unsigned int i = 0; + i < m_layers[m_active_layer].m_regions.size(); i++) + { + Region *reg = m_layers[m_active_layer].m_regions[i]; + if (!reg->inside(m_mouse.x, m_mouse.y)) + continue; + if (reg->update_alt_text(m_region_msg->alt_text())) + break; + } + } switch (event.type) { case SDL_KEYDOWN: m_key_mod |= _get_modifiers(event.key.keysym); key = _translate_keysym(event.key.keysym); + m_region_tile->place_cursor(CURSOR_MOUSE, Region::NO_CURSOR); // If you hit a key, disable tooltips until the mouse // is moved again. @@ -919,17 +939,21 @@ void TilesFramework::do_layout() if (message_overlay) { m_region_msg->resize_to_fit(m_region_tile->ex, m_region_msg->ey); - crawl_view.msgsz.x = m_region_msg->mx; - crawl_view.msgsz.y = m_region_msg->my; + m_region_msg->ex = m_region_tile->ex; } else { - m_region_msg->resize_to_fit(m_region_msg->wx, - m_windowsz.y - m_region_msg->sx); + m_region_msg->resize_to_fit(m_region_tile->wx, + m_windowsz.y - m_region_msg->sy); int msg_y = std::min(Options.msg_max_height, (int)m_region_msg->my); m_region_msg->resize(m_region_msg->mx, msg_y); + + m_region_msg->ex = m_region_tile->ex; + m_region_msg->ey = m_windowsz.y; } m_region_msg->set_overlay(message_overlay); + crawl_view.msgsz.x = m_region_msg->mx; + crawl_view.msgsz.y = m_region_msg->my; // Shrink view width if stat window can't fit... int stat_col; @@ -1121,9 +1145,9 @@ void TilesFramework::redraw() { const coord_def min_pos(0, 0); FTFont *font = m_fonts[m_tip_font].font; + font->render_string(m_mouse.x, m_mouse.y - 2, m_tooltip.c_str(), - min_pos, m_windowsz, WHITE, false, 150, - BLUE, 5); + min_pos, m_windowsz, WHITE, false, 220, BLUE, 5); } SDL_GL_SwapBuffers(); |