1 /**
2  * \file obj-desc.c
3  * \brief Create object name descriptions
4  *
5  * Copyright (c) 1997 - 2007 Angband contributors
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 
19 #include "angband.h"
20 #include "obj-chest.h"
21 #include "obj-desc.h"
22 #include "obj-gear.h"
23 #include "obj-ignore.h"
24 #include "obj-knowledge.h"
25 #include "obj-tval.h"
26 #include "obj-util.h"
27 
28 /**
29  * Puts the object base kind's name into buf.
30  */
object_base_name(char * buf,size_t max,int tval,bool plural)31 void object_base_name(char *buf, size_t max, int tval, bool plural)
32 {
33 	struct object_base *kb = &kb_info[tval];
34 	size_t end = 0;
35 
36 	if (kb->name && kb->name[0])
37 		(void) obj_desc_name_format(buf, max, end, kb->name, NULL, plural);
38 }
39 
40 
41 /**
42  * Puts a very stripped-down version of an object's name into buf.
43  * If easy_know is true, then the IDed names are used, otherwise
44  * flavours, scroll names, etc will be used.
45  *
46  * Just truncates if the buffer isn't big enough.
47  */
object_kind_name(char * buf,size_t max,const struct object_kind * kind,bool easy_know)48 void object_kind_name(char *buf, size_t max, const struct object_kind *kind,
49 					  bool easy_know)
50 {
51 	/* If not aware, the plain flavour (e.g. Copper) will do. */
52 	if (!easy_know && !kind->aware && kind->flavor)
53 		my_strcpy(buf, kind->flavor->text, max);
54 
55 	/* Use proper name (Healing, or whatever) */
56 	else
57 		(void) obj_desc_name_format(buf, max, 0, kind->name, NULL, false);
58 }
59 
60 
61 /**
62  * A modifier string, put where '#' goes in the basename below.  The weird
63  * games played with book names are to allow the non-essential part of the
64  * name to be abbreviated when there is not much room to display.
65  */
obj_desc_get_modstr(const struct object_kind * kind)66 static const char *obj_desc_get_modstr(const struct object_kind *kind)
67 {
68 	if (tval_can_have_flavor_k(kind))
69 		return kind->flavor ? kind->flavor->text : "";
70 
71 	if (tval_is_book_k(kind))
72 		return kind->name;
73 
74 	return "";
75 }
76 
77 /**
78  * An object's basic name - a generic name for flavored objects (with the
79  * actual name added later depending on awareness, the name from object.txt
80  * for almost everything else, and a bit extra for books.
81  */
obj_desc_get_basename(const struct object * obj,bool aware,bool terse,int mode)82 static const char *obj_desc_get_basename(const struct object *obj, bool aware,
83 										 bool terse, int mode)
84 {
85 	bool show_flavor = !terse && obj->kind->flavor;
86 
87 	if (mode & ODESC_STORE)
88 		show_flavor = false;
89 	if (aware && !OPT(player, show_flavors)) show_flavor = false;
90 
91 	/* Artifacts are special */
92 	if (obj->artifact && (aware || object_is_known_artifact(obj) || terse ||
93 						  !obj->kind->flavor))
94 		return obj->kind->name;
95 
96 	/* Analyze the object */
97 	switch (obj->tval)
98 	{
99 		case TV_FLASK:
100 		case TV_CHEST:
101 		case TV_SHOT:
102 		case TV_BOLT:
103 		case TV_ARROW:
104 		case TV_BOW:
105 		case TV_HAFTED:
106 		case TV_POLEARM:
107 		case TV_SWORD:
108 		case TV_DIGGING:
109 		case TV_BOOTS:
110 		case TV_GLOVES:
111 		case TV_CLOAK:
112 		case TV_CROWN:
113 		case TV_HELM:
114 		case TV_SHIELD:
115 		case TV_SOFT_ARMOR:
116 		case TV_HARD_ARMOR:
117 		case TV_DRAG_ARMOR:
118 		case TV_LIGHT:
119 		case TV_FOOD:
120 			return obj->kind->name;
121 
122 		case TV_AMULET:
123 			return (show_flavor ? "& # Amulet~" : "& Amulet~");
124 
125 		case TV_RING:
126 			return (show_flavor ? "& # Ring~" : "& Ring~");
127 
128 		case TV_STAFF:
129 			return (show_flavor ? "& # Sta|ff|ves|" : "& Sta|ff|ves|");
130 
131 		case TV_WAND:
132 			return (show_flavor ? "& # Wand~" : "& Wand~");
133 
134 		case TV_ROD:
135 			return (show_flavor ? "& # Rod~" : "& Rod~");
136 
137 		case TV_POTION:
138 			return (show_flavor ? "& # Potion~" : "& Potion~");
139 
140 		case TV_SCROLL:
141 			return (show_flavor ? "& Scroll~ titled #" : "& Scroll~");
142 
143 		case TV_MAGIC_BOOK:
144 			if (terse)
145 				return "& Book~ #";
146 			else
147 				return "& Book~ of Magic Spells #";
148 
149 		case TV_PRAYER_BOOK:
150 			if (terse)
151 				return "& Book~ #";
152 			else
153 				return "& Holy Book~ of Prayers #";
154 
155 		case TV_NATURE_BOOK:
156 			if (terse)
157 				return "& Book~ #";
158 			else
159 				return "& Book~ of Nature Magics #";
160 
161 		case TV_SHADOW_BOOK:
162 			if (terse)
163 				return "& Tome~ #";
164 			else
165 				return "& Necromantic Tome~ #";
166 
167 		case TV_OTHER_BOOK:
168 			if (terse)
169 				return "& Book~ #";
170 			else
171 				return "& Book of Mysteries~ #";
172 
173 		case TV_MUSHROOM:
174 			return (show_flavor ? "& # Mushroom~" : "& Mushroom~");
175 	}
176 
177 	return "(nothing)";
178 }
179 
180 
181 /**
182  * Start to description, indicating number/uniqueness (a, the, no more, 7, etc)
183  */
obj_desc_name_prefix(char * buf,size_t max,size_t end,const struct object * obj,const char * basename,const char * modstr,bool terse)184 static size_t obj_desc_name_prefix(char *buf, size_t max, size_t end,
185 		const struct object *obj, const char *basename,
186 		const char *modstr, bool terse)
187 {
188 	if (obj->number == 0) {
189 		strnfcat(buf, max, &end, "no more ");
190 	} else if (obj->number > 1) {
191 		strnfcat(buf, max, &end, "%d ", obj->number);
192 	} else if (object_is_known_artifact(obj)) {
193 		strnfcat(buf, max, &end, "the ");
194 	} else if (*basename == '&') {
195 		bool an = false;
196 		const char *lookahead = basename + 1;
197 
198 		while (*lookahead == ' ') lookahead++;
199 
200 		if (*lookahead == '#') {
201 			if (modstr && is_a_vowel(*modstr))
202 				an = true;
203 		} else if (is_a_vowel(*lookahead)) {
204 			an = true;
205 		}
206 
207 		if (!terse) {
208 			if (an)
209 				strnfcat(buf, max, &end, "an ");
210 			else
211 				strnfcat(buf, max, &end, "a ");
212 		}
213 	}
214 
215 	return end;
216 }
217 
218 
219 
220 /**
221  * Formats 'fmt' into 'buf', with the following formatting characters:
222  *
223  * '~' at the end of a word (e.g. "fridge~") will pluralise
224  *
225  * '|x|y|' will be output as 'x' if singular or 'y' if plural
226  *    (e.g. "kni|fe|ves|")
227  *
228  * '#' will be replaced with 'modstr' (which may contain the pluralising
229  * formats given above).
230  */
obj_desc_name_format(char * buf,size_t max,size_t end,const char * fmt,const char * modstr,bool pluralise)231 size_t obj_desc_name_format(char *buf, size_t max, size_t end,
232 		const char *fmt, const char *modstr, bool pluralise)
233 {
234 	/* Copy the string */
235 	while (*fmt) {
236 		/* Skip */
237 		if (*fmt == '&') {
238 			while (*fmt == ' ' || *fmt == '&')
239 				fmt++;
240 			continue;
241 		} else if (*fmt == '~') {
242 			/* Pluralizer (regular English plurals) */
243 			char prev = *(fmt - 1);
244 
245 			if (!pluralise)	{
246 				fmt++;
247 				continue;
248 			}
249 
250 			/* e.g. cutlass-e-s, torch-e-s, box-e-s */
251 			if (prev == 's' || prev == 'h' || prev == 'x')
252 				strnfcat(buf, max, &end, "es");
253 			else
254 				strnfcat(buf, max, &end, "s");
255 		} else if (*fmt == '|') {
256 			/* Special plurals
257 			* e.g. kni|fe|ves|
258 			*          ^  ^  ^ */
259 			const char *singular = fmt + 1;
260 			const char *plural   = strchr(singular, '|');
261 			const char *endmark  = NULL;
262 
263 			if (plural) {
264 				plural++;
265 				endmark = strchr(plural, '|');
266 			}
267 
268 			if (!singular || !plural || !endmark) return end;
269 
270 			if (!pluralise)
271 				strnfcat(buf, max, &end, "%.*s", plural - singular - 1,
272 						 singular);
273 			else
274 				strnfcat(buf, max, &end, "%.*s", endmark - plural, plural);
275 
276 			fmt = endmark;
277 		} else if (*fmt == '#') {
278 			/* Add modstr, with pluralisation if relevant */
279 			end = obj_desc_name_format(buf, max, end, modstr, NULL,	pluralise);
280 		}
281 
282 		else
283 			buf[end++] = *fmt;
284 
285 		fmt++;
286 	}
287 
288 	buf[end] = 0;
289 
290 	return end;
291 }
292 
293 
294 /**
295  * Format object obj's name into 'buf'.
296  */
obj_desc_name(char * buf,size_t max,size_t end,const struct object * obj,bool prefix,int mode,bool terse)297 static size_t obj_desc_name(char *buf, size_t max, size_t end,
298 		const struct object *obj, bool prefix, int mode, bool terse)
299 {
300 	bool store = mode & ODESC_STORE ? true : false;
301 	bool spoil = mode & ODESC_SPOIL ? true : false;
302 
303 	/* Actual name for flavoured objects if aware, or in store, or spoiled */
304 	bool aware = object_flavor_is_aware(obj) || store || spoil;
305 	/* Pluralize if (not forced singular) and
306 	 * (not a known/visible artifact) and
307 	 * (not one in stack or forced plural) */
308 	bool plural = !(mode & ODESC_SINGULAR) &&
309 		!obj->artifact &&
310 		(obj->number != 1 || (mode & ODESC_PLURAL));
311 	const char *basename = obj_desc_get_basename(obj, aware, terse, mode);
312 	const char *modstr = obj_desc_get_modstr(obj->kind);
313 
314 	/* Quantity prefix */
315 	if (prefix)
316 		end = obj_desc_name_prefix(buf, max, end, obj, basename, modstr, terse);
317 
318 	/* Base name */
319 	end = obj_desc_name_format(buf, max, end, basename, modstr, plural);
320 
321 	/* Append extra names of various kinds */
322 	if (object_is_known_artifact(obj))
323 		strnfcat(buf, max, &end, " %s", obj->artifact->name);
324 	else if ((obj->known->ego && !(mode & ODESC_NOEGO)) || (obj->ego && store))
325 		strnfcat(buf, max, &end, " %s", obj->ego->name);
326 	else if (aware && !obj->artifact &&
327 			 (obj->kind->flavor || obj->kind->tval == TV_SCROLL)) {
328 		if (terse)
329 			strnfcat(buf, max, &end, " '%s'", obj->kind->name);
330 		else
331 			strnfcat(buf, max, &end, " of %s", obj->kind->name);
332 	}
333 
334 	return end;
335 }
336 
337 /**
338  * Is obj armor?
339  */
obj_desc_show_armor(const struct object * obj)340 static bool obj_desc_show_armor(const struct object *obj)
341 {
342 	if (player->obj_k->ac && (obj->ac || tval_is_armor(obj))) return true;
343 
344 	return false;
345 }
346 
347 /**
348  * Special descriptions for types of chest traps
349  */
obj_desc_chest(const struct object * obj,char * buf,size_t max,size_t end)350 static size_t obj_desc_chest(const struct object *obj, char *buf, size_t max,
351 							 size_t end)
352 {
353 	if (!tval_is_chest(obj)) return end;
354 
355 	/* The chest is unopened, but we know nothing about its trap/lock */
356 	if (obj->pval && !obj->known->pval) return end;
357 
358 	/* Describe the traps */
359 	strnfcat(buf, max, &end, format(" (%s)", chest_trap_name(obj)));
360 
361 	return end;
362 }
363 
364 /**
365  * Describe combat properties of an item - damage dice, to-hit, to-dam, armor
366  * class, missile multipler
367  */
obj_desc_combat(const struct object * obj,char * buf,size_t max,size_t end,int mode)368 static size_t obj_desc_combat(const struct object *obj, char *buf, size_t max,
369 							  size_t end, int mode)
370 {
371 	bool spoil = mode & ODESC_SPOIL ? true : false;
372 
373 	/* Display damage dice if they are known */
374 	if (kf_has(obj->kind->kind_flags, KF_SHOW_DICE) &&
375 		(player->obj_k->dd && player->obj_k->ds))
376 		strnfcat(buf, max, &end, " (%dd%d)", obj->dd, obj->ds);
377 
378 	/* Display shooting power as part of the multiplier */
379 	if (kf_has(obj->kind->kind_flags, KF_SHOW_MULT))
380 		strnfcat(buf, max, &end, " (x%d)",
381 				 obj->pval + obj->modifiers[OBJ_MOD_MIGHT]);
382 
383 	/* No more if the object hasn't been assessed */
384 	if (!((obj->notice & OBJ_NOTICE_ASSESSED) || spoil)) return end;
385 
386 	/* Show weapon bonuses if we know of any */
387 	if (player->obj_k->to_h && player->obj_k->to_d &&
388 		(tval_is_weapon(obj) || obj->to_d ||
389 		 (obj->to_h && !tval_is_body_armor(obj)) ||
390 		 (!object_has_standard_to_h(obj) && !obj->artifact && !obj->ego))) {
391 		/* In general show full combat bonuses */
392 		strnfcat(buf, max, &end, " (%+d,%+d)", obj->to_h, obj->to_d);
393 	} else if (obj->to_h < 0 && object_has_standard_to_h(obj)) {
394 		/* Special treatment for body armor with only a to-hit penalty */
395 		strnfcat(buf, max, &end, " (%+d)", obj->to_h);
396 	} else if (obj->to_d != 0 && player->obj_k->to_d) {
397 		/* To-dam rune known only */
398 		strnfcat(buf, max, &end, " (%+d)", obj->to_d);
399 	} else if (obj->to_h != 0 && player->obj_k->to_h) {
400 		/* To-hit rune known only */
401 		strnfcat(buf, max, &end, " (%+d)", obj->to_h);
402 	}
403 
404 	/* Show armor bonuses */
405 	if (player->obj_k->to_a) {
406 		if (obj_desc_show_armor(obj))
407 			strnfcat(buf, max, &end, " [%d,%+d]", obj->ac, obj->to_a);
408 		else if (obj->to_a)
409 			strnfcat(buf, max, &end, " [%+d]", obj->to_a);
410 	} else if (obj_desc_show_armor(obj)) {
411 		strnfcat(buf, max, &end, " [%d]", obj->ac);
412 	}
413 
414 	return end;
415 }
416 
417 /**
418  * Describe remaining light for refuellable lights
419  */
obj_desc_light(const struct object * obj,char * buf,size_t max,size_t end)420 static size_t obj_desc_light(const struct object *obj, char *buf, size_t max,
421 							 size_t end)
422 {
423 	/* Fuelled light sources get number of remaining turns appended */
424 	if (tval_is_light(obj) && !of_has(obj->flags, OF_NO_FUEL))
425 		strnfcat(buf, max, &end, " (%d turns)", obj->timeout);
426 
427 	return end;
428 }
429 
430 /**
431  * Describe numerical modifiers to stats and other player qualities which
432  * allow numerical bonuses - speed, stealth, etc
433  */
obj_desc_mods(const struct object * obj,char * buf,size_t max,size_t end)434 static size_t obj_desc_mods(const struct object *obj, char *buf, size_t max,
435 							size_t end)
436 {
437 	int i, j, num_mods = 0;
438 	int mods[OBJ_MOD_MAX] = { 0 };
439 
440 	/* Run through possible modifiers and store distinct ones */
441 	for (i = 0; i < OBJ_MOD_MAX; i++) {
442 		/* Check for known non-zero mods */
443 		if (obj->modifiers[i] != 0) {
444 			/* If no mods stored yet, store and move on */
445 			if (!num_mods) {
446 				mods[num_mods++] = obj->modifiers[i];
447 				continue;
448 			}
449 
450 			/* Run through the existing mods, quit on duplicates */
451 			for (j = 0; j < num_mods; j++)
452 				if (mods[j] == obj->modifiers[i]) break;
453 
454 			/* Add another mod if needed */
455 			if (j == num_mods)
456 				mods[num_mods++] = obj->modifiers[i];
457 		}
458 	}
459 
460 	if (!num_mods) return end;
461 
462 	/* Print the modifiers */
463 	strnfcat(buf, max, &end, " <");
464 	for (j = 0; j < num_mods; j++) {
465 		if (j) strnfcat(buf, max, &end, ", ");
466 		strnfcat(buf, max, &end, "%+d", mods[j]);
467 	}
468 	strnfcat(buf, max, &end, ">");
469 
470 	return end;
471 }
472 
473 /**
474  * Describe charges or charging status for re-usable items with magic effects
475  */
obj_desc_charges(const struct object * obj,char * buf,size_t max,size_t end,int mode)476 static size_t obj_desc_charges(const struct object *obj, char *buf, size_t max,
477 							   size_t end, int mode)
478 {
479 	bool aware = object_flavor_is_aware(obj) || (mode & ODESC_STORE);
480 
481 	/* Wands and staffs have charges, others may be charging */
482 	if (aware && tval_can_have_charges(obj)) {
483 		strnfcat(buf, max, &end, " (%d charge%s)", obj->pval,
484 				 PLURAL(obj->pval));
485 	} else if (obj->timeout > 0) {
486 		if (tval_is_rod(obj) && obj->number > 1)
487 			strnfcat(buf, max, &end, " (%d charging)", number_charging(obj));
488 		else if (tval_is_rod(obj) || obj->activation || obj->effect)
489 			/* Artifacts, single rods */
490 			strnfcat(buf, max, &end, " (charging)");
491 	}
492 
493 	return end;
494 }
495 
496 /**
497  * Add player-defined inscriptions or game-defined descriptions
498  */
obj_desc_inscrip(const struct object * obj,char * buf,size_t max,size_t end)499 static size_t obj_desc_inscrip(const struct object *obj, char *buf,
500 							   size_t max, size_t end)
501 {
502 	const char *u[6] = { 0, 0, 0, 0, 0, 0 };
503 	int n = 0;
504 
505 	/* Get inscription */
506 	if (obj->note)
507 		u[n++] = quark_str(obj->note);
508 
509 	/* Use special inscription, if any */
510 	if (!object_flavor_is_aware(obj)) {
511 		if (tval_can_have_charges(obj) && (obj->pval == 0))
512 			u[n++] = "empty";
513 		if (object_flavor_was_tried(obj))
514 			u[n++] = "tried";
515 	}
516 
517 	/* Note curses */
518 	if (obj->known->curses)
519 		u[n++] = "cursed";
520 
521 	/* Note ignore */
522 	if (ignore_item_ok(obj))
523 		u[n++] = "ignore";
524 
525 	/* Note unknown properties */
526 	if (!object_runes_known(obj) && (obj->known->notice & OBJ_NOTICE_ASSESSED))
527 		u[n++] = "??";
528 
529 	if (n) {
530 		int i;
531 		for (i = 0; i < n; i++) {
532 			if (i == 0)
533 				strnfcat(buf, max, &end, " {");
534 			strnfcat(buf, max, &end, "%s", u[i]);
535 			if (i < n - 1)
536 				strnfcat(buf, max, &end, ", ");
537 		}
538 
539 		strnfcat(buf, max, &end, "}");
540 	}
541 
542 	return end;
543 }
544 
545 
546 /**
547  * Add "unseen" to the end of unaware items in stores,
548  * and "??" to not fully known unflavored items
549  */
obj_desc_aware(const struct object * obj,char * buf,size_t max,size_t end)550 static size_t obj_desc_aware(const struct object *obj, char *buf, size_t max,
551 							 size_t end)
552 {
553 	if (!object_flavor_is_aware(obj)) {
554 		strnfcat(buf, max, &end, " {unseen}");
555 	} else if (!object_runes_known(obj)) {
556 		strnfcat(buf, max, &end, " {??}");
557 	} else if (obj->known->curses) {
558 		strnfcat(buf, max, &end, " {cursed}");
559 	}
560 
561 	return end;
562 }
563 
564 
565 /**
566  * Describes item `obj` into buffer `buf` of size `max`.
567  *
568  * ODESC_PREFIX prepends a 'the', 'a' or number
569  * ODESC_BASE results in a base description.
570  * ODESC_COMBAT will add to-hit, to-dam and AC info.
571  * ODESC_EXTRA will add pval/charge/inscription/ignore info.
572  * ODESC_PLURAL will pluralise regardless of the number in the stack.
573  * ODESC_STORE turns off ignore markers, for in-store display.
574  * ODESC_SPOIL treats the object as fully identified.
575  *
576  * Setting 'prefix' to true prepends a 'the', 'a' or the number in the stack,
577  * respectively.
578  *
579  * \returns The number of bytes used of the buffer.
580  */
object_desc(char * buf,size_t max,const struct object * obj,int mode)581 size_t object_desc(char *buf, size_t max, const struct object *obj, int mode)
582 {
583 	bool prefix = mode & ODESC_PREFIX ? true : false;
584 	bool spoil = mode & ODESC_SPOIL ? true : false;
585 	bool terse = mode & ODESC_TERSE ? true : false;
586 
587 	size_t end = 0;
588 
589 	/* Simple description for null item */
590 	if (!obj || !obj->known)
591 		return strnfmt(buf, max, "(nothing)");
592 
593 	/* Unknown itema and cash get straightforward descriptions */
594 	if (obj->known && obj->kind != obj->known->kind) {
595 		if (prefix)
596 			return strnfmt(buf, max, "an unknown item");
597 		return strnfmt(buf, max, "unknown item");
598 	}
599 
600 	if (tval_is_money(obj))
601 		return strnfmt(buf, max, "%d gold pieces worth of %s%s",
602 				obj->pval, obj->kind->name,
603 				ignore_item_ok(obj) ? " {ignore}" : "");
604 
605 	/* Egos and kinds whose name we know are seen */
606 	if (obj->known->ego && !spoil)
607 		obj->ego->everseen = true;
608 
609 	if (object_flavor_is_aware(obj) && !spoil)
610 		obj->kind->everseen = true;
611 
612 	/** Construct the name **/
613 
614 	/* Copy the base name to the buffer */
615 	end = obj_desc_name(buf, max, end, obj, prefix, mode, terse);
616 
617 	/* Combat properties */
618 	if (mode & ODESC_COMBAT) {
619 		if (tval_is_chest(obj))
620 			end = obj_desc_chest(obj, buf, max, end);
621 		else if (tval_is_light(obj))
622 			end = obj_desc_light(obj, buf, max, end);
623 
624 		end = obj_desc_combat(obj->known, buf, max, end, mode);
625 	}
626 
627 	/* Modifiers, charges, flavour details, inscriptions */
628 	if (mode & ODESC_EXTRA) {
629 		end = obj_desc_mods(obj->known, buf, max, end);
630 
631 		end = obj_desc_charges(obj, buf, max, end, mode);
632 
633 		if (mode & ODESC_STORE)
634 			end = obj_desc_aware(obj, buf, max, end);
635 		else
636 			end = obj_desc_inscrip(obj, buf, max, end);
637 	}
638 
639 	return end;
640 }
641