static void describe_flavor_text(textblock *tb, const object_type *o_ptr) { /* Display the known artifact description */ if (!OPT(birth_randarts) && o_ptr->artifact && object_name_is_visible(o_ptr) && o_ptr->artifact->text) textblock_append(tb, "%s\n\n", o_ptr->artifact->text); /* Display the known object description */ else if (object_flavor_is_aware(o_ptr) || object_is_known(o_ptr)) { bool did_desc = FALSE; if (o_ptr->kind->text) { textblock_append(tb, "%s", o_ptr->kind->text); did_desc = TRUE; } /* Display an additional ego-item description */ if (object_ego_is_visible(o_ptr) && o_ptr->ego->text) { if (did_desc) textblock_append(tb, " "); textblock_append(tb, "%s\n\n", o_ptr->ego->text); } else if (did_desc) { textblock_append(tb, "\n\n"); } } }
/** * Describes item `obj` into buffer `buf` of size `max`. * * ODESC_PREFIX prepends a 'the', 'a' or number * ODESC_BASE results in a base description. * ODESC_COMBAT will add to-hit, to-dam and AC info. * ODESC_EXTRA will add pval/charge/inscription/ignore info. * ODESC_PLURAL will pluralise regardless of the number in the stack. * ODESC_STORE turns off ignore markers, for in-store display. * ODESC_SPOIL treats the object as fully identified. * * Setting 'prefix' to TRUE prepends a 'the', 'a' or the number in the stack, * respectively. * * \returns The number of bytes used of the buffer. */ size_t object_desc(char *buf, size_t max, const struct object *obj, int mode) { bool prefix = mode & ODESC_PREFIX ? TRUE : FALSE; bool spoil = mode & ODESC_SPOIL ? TRUE : FALSE; bool terse = mode & ODESC_TERSE ? TRUE : FALSE; size_t end = 0; /* Simple description for null item */ if (!obj) return strnfmt(buf, max, "(nothing)"); /* Egos whose name we know are seen */ if (object_name_is_visible(obj) && obj->ego && !spoil) obj->ego->everseen = TRUE; /*** Some things get really simple descriptions ***/ if (obj->marked == MARK_AWARE) { if (prefix) return strnfmt(buf, max, "an unknown item"); return strnfmt(buf, max, "unknown item"); } if (tval_is_money(obj)) return strnfmt(buf, max, "%d gold pieces worth of %s%s", obj->pval, obj->kind->name, ignore_item_ok(obj) ? " {ignore}" : ""); /** Construct the name **/ /* Copy the base name to the buffer */ end = obj_desc_name(buf, max, end, obj, prefix, mode, spoil, terse); if (mode & ODESC_COMBAT) { if (tval_is_chest(obj)) end = obj_desc_chest(obj, buf, max, end); else if (tval_is_light(obj)) end = obj_desc_light(obj, buf, max, end); end = obj_desc_combat(obj, buf, max, end, spoil); } if (mode & ODESC_EXTRA) { end = obj_desc_mods(obj, buf, max, end, spoil); end = obj_desc_charges(obj, buf, max, end, mode); if (mode & ODESC_STORE) end = obj_desc_aware(obj, buf, max, end); else end = obj_desc_inscrip(obj, buf, max, end); } return end; }
/** * Remove an amount of an object from the inventory or quiver, returning * a detached object which can be used. * * Optionally describe what remains. */ struct object *gear_object_for_use(struct object *obj, int num, bool message) { struct object *usable; char name[80]; char label = gear_to_label(obj); bool artifact = obj->artifact && (object_is_known(obj) || object_name_is_visible(obj)); /* Bounds check */ num = MIN(num, obj->number); /* Prepare a name if necessary */ if (message) { /* Artifacts */ if (artifact) object_desc(name, sizeof(name), obj, ODESC_FULL | ODESC_SINGULAR); else { /* Describe as if it's already reduced */ obj->number -= num; object_desc(name, sizeof(name), obj, ODESC_PREFIX | ODESC_FULL); obj->number += num; } } /* Split off a usable object if necessary */ if (obj->number > num) { usable = object_split(obj, num); } else { /* We're using the entire stack */ usable = obj; gear_excise_object(usable); /* Stop tracking item */ if (tracked_object_is(player->upkeep, obj)) track_object(player->upkeep, NULL); /* Inventory has changed, so disable repeat command */ cmd_disable_repeat(); } /* Change the weight */ player->upkeep->total_weight -= (num * obj->weight); /* Housekeeping */ player->upkeep->update |= (PU_BONUS); player->upkeep->notice |= (PN_COMBINE); player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); /* Print a message if desired */ if (message) { if (artifact) msg("You no longer have the %s (%c).", name, label); else msg("You have %s (%c).", name, label); } return usable; }
/** * Format object obj's name into 'buf'. */ static size_t obj_desc_name(char *buf, size_t max, size_t end, const struct object *obj, bool prefix, int mode, bool spoil, bool terse) { bool known = object_is_known(obj) || spoil; bool aware = object_flavor_is_aware(obj) || (mode & ODESC_STORE) || spoil; const char *basename = obj_desc_get_basename(obj, aware, terse, mode); const char *modstr = obj_desc_get_modstr(obj->kind); if (aware && !obj->kind->everseen && !spoil) obj->kind->everseen = TRUE; if (prefix) end = obj_desc_name_prefix(buf, max, end, obj, known, basename, modstr, terse); /* Pluralize if (not forced singular) and * (not a known/visible artifact) and * (not one in stack or forced plural) */ end = obj_desc_name_format(buf, max, end, basename, modstr, !(mode & ODESC_SINGULAR) && !(obj->artifact && (object_name_is_visible(obj) || known)) && (obj->number != 1 || (mode & ODESC_PLURAL))); /** Append extra names of various kinds **/ if ((object_name_is_visible(obj) || known) && obj->artifact) strnfcat(buf, max, &end, " %s", obj->artifact->name); else if (((spoil && obj->ego) || object_ego_is_visible(obj)) && !(mode & ODESC_NOEGO)) strnfcat(buf, max, &end, " %s", obj->ego->name); else if (aware && !obj->artifact && (obj->kind->flavor || obj->kind->tval == TV_SCROLL)) { if (terse) strnfcat(buf, max, &end, " '%s'", obj->kind->name); else strnfcat(buf, max, &end, " of %s", obj->kind->name); } return end; }
/** * Start to description, indicating number/uniqueness (a, the, no more, 7, etc) */ static size_t obj_desc_name_prefix(char *buf, size_t max, size_t end, const struct object *obj, bool known, const char *basename, const char *modstr, bool terse) { if (obj->number == 0) strnfcat(buf, max, &end, "no more "); else if (obj->number > 1) strnfcat(buf, max, &end, "%d ", obj->number); else if ((object_name_is_visible(obj) || known) && obj->artifact) strnfcat(buf, max, &end, "the "); else if (*basename == '&') { bool an = FALSE; const char *lookahead = basename + 1; while (*lookahead == ' ') lookahead++; if (*lookahead == '#') { if (modstr && is_a_vowel(*modstr)) an = TRUE; } else if (is_a_vowel(*lookahead)) { an = TRUE; } if (!terse) { if (an) strnfcat(buf, max, &end, "an "); else strnfcat(buf, max, &end, "a "); } } return end; }
/* * Copy 'src' into 'buf, replacing '#' with 'modstr' (if found), putting a plural * in the place indicated by '~' if required, or using alterate... */ static size_t obj_desc_name(char *buf, size_t max, size_t end, const object_type *o_ptr, bool prefix, odesc_detail_t mode, bool spoil) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; bool known = object_is_known(o_ptr) || (o_ptr->ident & IDENT_STORE) || spoil; bool aware = object_flavor_is_aware(o_ptr) || (o_ptr->ident & IDENT_STORE) || spoil; const char *basename = obj_desc_get_basename(o_ptr, aware); const char *modstr = obj_desc_get_modstr(o_ptr); bool pluralise = (mode & ODESC_PLURAL) ? TRUE : FALSE; if (aware && !k_ptr->everseen) k_ptr->everseen = TRUE; if (o_ptr->number > 1) pluralise = TRUE; if (mode & ODESC_SINGULAR) pluralise = FALSE; /* Add a pseudo-numerical prefix if desired */ if (prefix) { if (o_ptr->number <= 0) { strnfcat(buf, max, &end, "no more "); /* Pluralise for grammatical correctness */ pluralise = TRUE; } else if (o_ptr->number > 1) strnfcat(buf, max, &end, "%d ", o_ptr->number); else if ((object_name_is_visible(o_ptr) || known) && artifact_p(o_ptr)) strnfcat(buf, max, &end, "The "); else if (*basename == '&') { bool an = FALSE; const char *lookahead = basename + 1; while (*lookahead == ' ') lookahead++; if (*lookahead == '#') { if (modstr && is_a_vowel(*modstr)) an = TRUE; } else if (is_a_vowel(*lookahead)) { an = TRUE; } if (an) strnfcat(buf, max, &end, "an "); else strnfcat(buf, max, &end, "a "); } } /* * Names have the following elements: * * '~' indicates where to place an 's' or an 'es'. Other plural forms should * be handled with the syntax '|singular|plural|', e.g. "kni|fe|ves|". * * '#' indicates the position of the "modifier", e.g. the flavour or spellbook * name. */ /* Copy the string */ while (*basename) { if (*basename == '&') { while (*basename == ' ' || *basename == '&') basename++; continue; } /* Pluralizer (regular English plurals) */ else if (*basename == '~') { char prev = *(basename - 1); if (!pluralise) { basename++; continue; } /* e.g. cutlass-e-s, torch-e-s, box-e-s */ if (prev == 's' || prev == 'h' || prev == 'x') strnfcat(buf, max, &end, "es"); else strnfcat(buf, max, &end, "s"); } /* Special plurals */ else if (*basename == '|') { /* e.g. & Wooden T|o|e|rch~ * ^ ^^ */ const char *singular = basename + 1; const char *plural = strchr(singular, '|'); const char *endmark = NULL; if (plural) { plural++; endmark = strchr(plural, '|'); } if (!singular || !plural || !endmark) return end; if (!pluralise) strnfcat(buf, max, &end, "%.*s", plural - singular - 1, singular); else strnfcat(buf, max, &end, "%.*s", endmark - plural, plural); basename = endmark; } /* Handle pluralisation in the modifier XXX */ else if (*basename == '#') { const char *basename = modstr; while (basename && *basename && (end < max - 1)) { /* Special plurals */ if (*basename == '|') { /* e.g. & Wooden T|o|e|rch~ * ^ ^^ */ const char *singular = basename + 1; const char *plural = strchr(singular, '|'); const char *endmark = NULL; if (plural) { plural++; endmark = strchr(plural, '|'); } if (!singular || !plural || !endmark) return end; if (!pluralise) strnfcat(buf, max, &end, "%.*s", plural - singular - 1, singular); else strnfcat(buf, max, &end, "%.*s", endmark - plural, plural); basename = endmark; } else buf[end++] = *basename; basename++; } } else buf[end++] = *basename; basename++; } /* 0-terminate, just in case XXX */ buf[end] = 0; /** Append extra names of various kinds **/ if ((object_name_is_visible(o_ptr) || known) && o_ptr->name1) strnfcat(buf, max, &end, " %s", a_name + a_info[o_ptr->name1].name); else if ((spoil && o_ptr->name2) || object_ego_is_visible(o_ptr)) strnfcat(buf, max, &end, " %s", e_name + e_info[o_ptr->name2].name); else if (aware && !artifact_p(o_ptr) && (k_ptr->flavor || k_ptr->tval == TV_SCROLL)) strnfcat(buf, max, &end, " of %s", k_name + k_ptr->name); return end; }