Apply the new ground_level method.
[crawl.git] / crawl-ref / source / describe.h
blobd453eeb596532ae975bc9f195c1a665d0d3c2754
2 /*
3 * File: describe.h
4 * Summary: Functions used to print information about various game objects.
5 * Written by: Linley Henzell
6 */
8 #ifndef DESCRIBE_H
9 #define DESCRIBE_H
11 #include <string>
12 #include <sstream>
13 #include "externs.h"
14 #include "enum.h"
15 #include "mon-info.h"
17 // If you add any more description types, remember to also
18 // change item_description in externs.h
19 enum item_description_type
21 IDESC_WANDS = 0,
22 IDESC_POTIONS,
23 IDESC_SCROLLS, // special field (like the others)
24 IDESC_RINGS,
25 IDESC_SCROLLS_II,
26 IDESC_STAVES,
27 NUM_IDESC
30 enum book_mem_or_forget
32 BOOK_MEM,
33 BOOK_FORGET,
34 BOOK_NEITHER
37 struct describe_info
39 std::ostringstream body;
40 std::string title;
41 std::string prefix;
42 std::string suffix;
43 std::string footer;
44 std::string quote;
47 void append_spells(std::string &desc, const item_def &item);
49 bool is_dumpable_artefact(const item_def &item, bool verbose);
51 std::string get_item_description(const item_def &item, bool verbose,
52 bool dump = false, bool noquote = false);
54 std::string god_title(god_type which_god, species_type which_species);
55 void describe_god(god_type which_god, bool give_title);
57 void describe_feature_wide(const coord_def& pos, bool show_quote = false);
58 void get_feature_desc(const coord_def &gc, describe_info &inf);
60 void set_feature_desc_long(const std::string &raw_name,
61 const std::string &desc);
63 void set_feature_quote(const std::string &raw_name,
64 const std::string &quote);
66 bool describe_item(item_def &item, bool allow_inscribe = false,
67 bool shopping = false);
68 void get_item_desc(const item_def &item, describe_info &inf,
69 bool terse = false);
70 void inscribe_item(item_def &item, bool msgwin);
72 void append_weapon_stats(std::string &description, const item_def &item);
73 void append_armour_stats(std::string &description, const item_def &item);
74 void append_missile_info(std::string &description);
76 void describe_monsters(const monster_info &mi, bool force_seen = false,
77 const std::string &footer = "",
78 bool wait_until_key_pressed = true,
79 bool show_quote = false);
81 void get_monster_db_desc(const monster_info &mi, describe_info &inf,
82 bool &has_stat_desc, bool force_seen = false);
84 void get_spell_desc(const spell_type spell, describe_info &inf);
85 void describe_spell(spell_type spelled, const item_def* item = NULL);
87 std::string short_ghost_description(const monster *mon, bool abbrev = false);
88 std::string get_ghost_description(const monster_info &mi, bool concise = false);
90 std::string get_skill_description(skill_type skill, bool need_title = false);
92 void describe_skill(skill_type skill);
94 #ifdef USE_TILE
95 std::string get_command_description(const command_type cmd,
96 bool terse);
97 #endif
99 void print_description(const std::string &desc);
100 void print_description(const describe_info &inf);
102 void print_quote (const describe_info &inf);
103 void print_quote (const std::string &desc);
105 template<class T> void process_description(T &proc, const describe_info &inf);
106 template<class T> void process_quote(T &proc, const describe_info &inf);
108 void trim_randart_inscrip(item_def& item);
109 std::string artefact_auto_inscription(const item_def& item);
110 void add_autoinscription(item_def &item, std::string ainscrip);
111 void add_autoinscription(item_def &item);
112 void add_inscription(item_def &item, std::string inscrip);
114 const char *trap_name(trap_type trap);
115 int str_to_trap(const std::string &s);
117 int count_desc_lines(const std::string _desc, const int width);
119 class alt_desc_proc
121 public:
122 alt_desc_proc(int _w, int _h) { w = _w; h = _h; }
124 int width() { return w; }
125 int height() { return h; }
127 void nextline();
128 void print(const std::string &str);
129 static int count_newlines(const std::string &str);
131 // Remove trailing newlines.
132 static void trim(std::string &str);
133 // rfind consecutive newlines and truncate.
134 static bool chop(std::string &str);
136 void get_string(std::string &str);
138 protected:
139 int w;
140 int h;
141 std::ostringstream ostr;
144 /* ***********************************************************************
145 * template implementations
146 * *********************************************************************** */
147 // My kingdom for a closure.
148 template<class T>
149 inline void process_description(T &proc, const describe_info &inf)
151 const unsigned int line_width = proc.width();
152 const int height = proc.height();
154 std::string desc;
156 // How many lines is the title; we also seem to be adding 1 to
157 // start with.
158 int num_lines = count_desc_lines(inf.title, line_width) + 1;
160 int body_lines = count_desc_lines(inf.body.str(), line_width);
161 const int suffix_lines = count_desc_lines(inf.suffix, line_width);
162 const int prefix_lines = count_desc_lines(inf.prefix, line_width);
163 const int footer_lines = count_desc_lines(inf.footer, line_width)
164 + (inf.footer.empty() ? 0 : 1);
166 // Maybe skip the body if body + title would be too many lines.
167 if (inf.title.empty())
169 desc = inf.body.str();
170 // There is a default 1 line addition for some reason.
171 num_lines = body_lines + 1;
173 else if (body_lines + num_lines + 2 <= height)
175 desc = inf.title + "\n\n";
176 desc += inf.body.str();
177 // Got 2 lines from the two \ns that weren't counted yet.
178 num_lines += body_lines + 2;
180 else
181 desc = inf.title + "\n";
183 // Prefer the footer over the suffix.
184 if (num_lines + suffix_lines + footer_lines <= height)
186 desc = desc + inf.suffix;
187 num_lines += suffix_lines;
190 // Prefer the footer over the prefix.
191 if (num_lines + prefix_lines + footer_lines <= height)
193 desc = inf.prefix + desc;
194 num_lines += prefix_lines;
197 if (!inf.footer.empty() && num_lines + footer_lines <= height)
199 const int bottom_line = std::min(std::max(24, num_lines + 2),
200 height - footer_lines + 1);
201 const int newlines = bottom_line - num_lines;
203 if (newlines >= 0)
205 desc.append(newlines, '\n');
206 desc = desc + inf.footer;
210 std::string::size_type nextLine = std::string::npos;
211 unsigned int currentPos = 0;
213 while (currentPos < desc.length())
215 if (currentPos != 0)
216 proc.nextline();
218 // See if '\n' is within one line_width.
219 nextLine = desc.find('\n', currentPos);
221 if (nextLine >= currentPos && nextLine < currentPos + line_width)
223 proc.print(desc.substr(currentPos, nextLine-currentPos));
224 currentPos = nextLine + 1;
225 continue;
228 // Handle real line breaks. No substitutions necessary, just update
229 // the counts.
230 nextLine = desc.find('\n', currentPos);
231 if (nextLine >= currentPos && nextLine < currentPos + line_width)
233 proc.print(desc.substr(currentPos, nextLine-currentPos));
234 currentPos = nextLine + 1;
235 continue;
238 // No newline -- see if rest of string will fit.
239 if (currentPos + line_width >= desc.length())
241 proc.print(desc.substr(currentPos));
242 return;
246 // Ok, try to truncate at space.
247 nextLine = desc.rfind(' ', currentPos + line_width);
249 if (nextLine > 0)
251 proc.print(desc.substr(currentPos, nextLine - currentPos));
252 currentPos = nextLine + 1;
253 continue;
256 // Oops. Just truncate.
257 nextLine = currentPos + line_width;
259 nextLine = std::min(inf.body.str().length(), nextLine);
261 proc.print(desc.substr(currentPos, nextLine - currentPos));
262 currentPos = nextLine;
266 template<class T>
267 inline void process_quote(T &proc, const describe_info &inf)
269 const unsigned int line_width = proc.width();
270 const int height = proc.height();
272 std::string desc;
274 // How many lines is the title; we also seem to be adding 1 to
275 // start with.
276 int num_lines = count_desc_lines(inf.title, line_width) + 1;
278 int body_lines = count_desc_lines(inf.quote, line_width);
280 // Maybe skip the body if body + title would be too many lines.
281 if (inf.title.empty())
283 desc = inf.quote;
284 // There is a default 1 line addition for some reason.
285 num_lines = body_lines + 1;
287 else if (body_lines + num_lines + 2 <= height)
289 desc = inf.title + "\n\n";
290 desc += inf.quote;
291 // Got 2 lines from the two \ns that weren't counted yet.
292 num_lines += body_lines + 2;
294 else
295 desc = inf.title + "\n";
297 if (num_lines <= height)
299 const int bottom_line = std::min(std::max(24, num_lines + 2),
300 height);
301 const int newlines = bottom_line - num_lines;
303 if (newlines >= 0)
305 desc.append(newlines, '\n');
309 std::string::size_type nextLine = std::string::npos;
310 unsigned int currentPos = 0;
312 while (currentPos < desc.length())
314 if (currentPos != 0)
315 proc.nextline();
317 // See if '\n' is within one line_width.
318 nextLine = desc.find('\n', currentPos);
320 if (nextLine >= currentPos && nextLine < currentPos + line_width)
322 proc.print(desc.substr(currentPos, nextLine-currentPos));
323 currentPos = nextLine + 1;
324 continue;
327 // Handle real line breaks. No substitutions necessary, just update
328 // the counts.
329 nextLine = desc.find('\n', currentPos);
330 if (nextLine >= currentPos && nextLine < currentPos + line_width)
332 proc.print(desc.substr(currentPos, nextLine-currentPos));
333 currentPos = nextLine + 1;
334 continue;
337 // No newline -- see if rest of string will fit.
338 if (currentPos + line_width >= desc.length())
340 proc.print(desc.substr(currentPos));
341 return;
345 // Ok, try to truncate at space.
346 nextLine = desc.rfind(' ', currentPos + line_width);
348 if (nextLine > 0)
350 proc.print(desc.substr(currentPos, nextLine - currentPos));
351 currentPos = nextLine + 1;
352 continue;
355 // Oops. Just truncate.
356 nextLine = currentPos + line_width;
358 nextLine = std::min(inf.body.str().length(), nextLine);
360 proc.print(desc.substr(currentPos, nextLine - currentPos));
361 currentPos = nextLine;
365 #endif