1 #include "flavor/named-item-describer.h"
2 #include "artifact/fixed-art-types.h"
3 #include "flavor/flavor-util.h"
4 #include "flavor/object-flavor-types.h"
5 #include "flavor/tval-description-switcher.h"
6 #include "game-option/text-display-options.h"
7 #include "locale/english.h"
8 #include "mind/mind-weaponsmith.h"
9 #include "object-enchant/object-ego.h"
10 #include "object-enchant/special-object-flags.h"
11 #include "object-enchant/tr-types.h"
12 #include "object/object-flags.h"
13 #include "perception/object-perception.h"
14 #include "system/artifact-type-definition.h"
15 #include "system/item-entity.h"
16 #include "system/player-type-definition.h"
17 #include "util/bit-flags-calculator.h"
18 #include "util/quarks.h"
19 #include "util/string-processor.h"
22 #include "monster-race/monster-race.h"
23 #include "monster-race/race-flags1.h"
24 #include "object/tval-types.h"
25 #include "system/monster-race-definition.h"
28 static void check_object_known_aware(flavor_type *flavor_ptr)
30 flavor_ptr->tr_flags = object_flags(flavor_ptr->o_ptr);
31 if (flavor_ptr->o_ptr->is_aware()) {
32 flavor_ptr->aware = true;
35 if (flavor_ptr->o_ptr->is_known()) {
36 flavor_ptr->known = true;
39 if (flavor_ptr->aware && ((flavor_ptr->mode & OD_NO_FLAVOR) || plain_descriptions)) {
40 flavor_ptr->flavor = false;
43 if ((flavor_ptr->mode & OD_STORE) || (flavor_ptr->o_ptr->ident & IDENT_STORE)) {
44 flavor_ptr->flavor = false;
45 flavor_ptr->aware = true;
46 flavor_ptr->known = true;
49 if (flavor_ptr->mode & OD_FORCE_FLAVOR) {
50 flavor_ptr->aware = false;
51 flavor_ptr->flavor = true;
52 flavor_ptr->known = false;
53 flavor_ptr->flavor_k_ptr = flavor_ptr->k_ptr;
57 static void set_base_name(flavor_type *flavor_ptr)
59 if (!flavor_ptr->aware || flavor_ptr->tr_flags.has_not(TR_FULL_NAME)) {
63 const auto fixed_art_id = flavor_ptr->o_ptr->fixed_artifact_idx;
64 const auto is_known_artifact = flavor_ptr->known && flavor_ptr->o_ptr->is_fixed_artifact() && none_bits(flavor_ptr->mode, OD_BASE_NAME);
65 flavor_ptr->basenm = is_known_artifact ? artifacts_info.at(fixed_art_id).name.data() : flavor_ptr->kindname;
69 static void describe_prefix_ja(flavor_type *flavor_ptr)
71 flavor_ptr->s = flavor_ptr->basenm[0] == '&' ? flavor_ptr->basenm + 2 : flavor_ptr->basenm;
72 if (flavor_ptr->mode & OD_OMIT_PREFIX) {
76 if (flavor_ptr->o_ptr->number > 1) {
77 flavor_ptr->t = object_desc_count_japanese(flavor_ptr->t, flavor_ptr->o_ptr);
78 flavor_ptr->t = object_desc_str(flavor_ptr->t, "の ");
83 * @brief アーティファクトの表記処理
84 * @param アイテム表記への参照ポインタ
85 * @details 英語の場合アーティファクトは The が付くので分かるが、日本語では分からないのでマークをつける.
87 static void describe_artifact_prefix_ja(flavor_type *flavor_ptr)
89 if (!flavor_ptr->known || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
93 if (flavor_ptr->o_ptr->is_fixed_artifact()) {
94 flavor_ptr->t = object_desc_str(flavor_ptr->t, "★");
95 } else if (flavor_ptr->o_ptr->art_name) {
96 flavor_ptr->t = object_desc_str(flavor_ptr->t, "☆");
101 * @brief アーティファクトの説明表記
102 * @param flavor_ptr アイテム表記への参照ポインタ
103 * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
105 static void describe_artifact_ja(flavor_type *flavor_ptr)
107 if (!flavor_ptr->known || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
111 if (flavor_ptr->o_ptr->art_name) {
112 concptr temp = quark_str(flavor_ptr->o_ptr->art_name);
114 /* '『' から始まらない伝説のアイテムの名前は最初に付加する */
115 /* 英語版のセーブファイルから来た 'of XXX' は,「XXXの」と表示する */
116 if (strncmp(temp, "of ", 3) == 0) {
117 flavor_ptr->t = object_desc_str(flavor_ptr->t, &temp[3]);
118 flavor_ptr->t = object_desc_str(flavor_ptr->t, "の");
119 } else if ((strncmp(temp, "『", 2) != 0) && (strncmp(temp, "《", 2) != 0) && (temp[0] != '\'')) {
120 flavor_ptr->t = object_desc_str(flavor_ptr->t, temp);
126 if (flavor_ptr->o_ptr->is_fixed_artifact() && flavor_ptr->tr_flags.has_not(TR_FULL_NAME)) {
127 const auto &a_ref = artifacts_info.at(flavor_ptr->o_ptr->fixed_artifact_idx);
128 /* '『' から始まらない伝説のアイテムの名前は最初に付加する */
129 if (a_ref.name.find("『", 0, 2) != 0) {
130 flavor_ptr->t = object_desc_str(flavor_ptr->t, a_ref.name.data());
136 if (flavor_ptr->o_ptr->is_ego()) {
137 auto *e_ptr = &egos_info[flavor_ptr->o_ptr->ego_idx];
138 flavor_ptr->t = object_desc_str(flavor_ptr->t, e_ptr->name.data());
143 * @brief ランダムアーティファクトの表記
144 * @param flavor_ptr アイテム表記への参照ポインタ
145 * @return ランダムアーティファクトならTRUE、違うならFALSE
146 * @details ランダムアーティファクトの名前はセーブファイルに記録されるので、英語版の名前もそれらしく変換する.
148 static bool describe_random_artifact_body_ja(flavor_type *flavor_ptr)
150 if (flavor_ptr->o_ptr->art_name == 0) {
156 strcpy(temp, quark_str(flavor_ptr->o_ptr->art_name));
157 if (strncmp(temp, "『", 2) == 0 || strncmp(temp, "《", 2) == 0) {
158 flavor_ptr->t = object_desc_str(flavor_ptr->t, temp);
162 if (temp[0] != '\'') {
166 itemp = strlen(temp);
168 flavor_ptr->t = object_desc_str(flavor_ptr->t, "『");
169 flavor_ptr->t = object_desc_str(flavor_ptr->t, &temp[1]);
170 flavor_ptr->t = object_desc_str(flavor_ptr->t, "』");
174 static void describe_ego_body_ja(flavor_type *flavor_ptr)
176 if (!flavor_ptr->o_ptr->inscription) {
180 concptr str = quark_str(flavor_ptr->o_ptr->inscription);
198 concptr str_aux = angband_strchr(quark_str(flavor_ptr->o_ptr->inscription), '#');
199 flavor_ptr->t = object_desc_str(flavor_ptr->t, "『");
200 flavor_ptr->t = object_desc_str(flavor_ptr->t, &str_aux[1]);
201 flavor_ptr->t = object_desc_str(flavor_ptr->t, "』");
205 * @brief アーティファクトのアイテム名を表記する
206 * @param flavor_ptr アイテム表記への参照ポインタ
207 * @details '『'から始まる伝説のアイテムの名前は最後に付加する
209 static void describe_artifact_body_ja(flavor_type *flavor_ptr)
211 if (!flavor_ptr->known || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
215 if (describe_random_artifact_body_ja(flavor_ptr)) {
219 if (flavor_ptr->o_ptr->is_fixed_artifact()) {
220 const auto &a_ref = artifacts_info.at(flavor_ptr->o_ptr->fixed_artifact_idx);
221 if (a_ref.name.find("『", 0, 2) == 0) {
222 flavor_ptr->t = object_desc_str(flavor_ptr->t, a_ref.name.data());
228 describe_ego_body_ja(flavor_ptr);
232 static void describe_vowel(flavor_type *flavor_ptr)
235 switch (*flavor_ptr->s) {
237 vowel = is_a_vowel(flavor_ptr->modstr[0]);
240 vowel = is_a_vowel(*flavor_ptr->kindname);
243 vowel = is_a_vowel(*flavor_ptr->s);
248 flavor_ptr->t = object_desc_str(flavor_ptr->t, "an ");
250 flavor_ptr->t = object_desc_str(flavor_ptr->t, "a ");
255 * @brief Process to write the number of items when there are 0, 1, or 2 or more.
256 * @param flavor_ptr Reference pointer to item's flavor
257 * @return If the number of items is 1, then FALE is returned, and if 0 or 2 or more, then TRUE is returned
258 * @details If the number of items is 1, then the continuous process will be run.
260 static bool describe_prefix_en(flavor_type *flavor_ptr)
262 if (flavor_ptr->o_ptr->number <= 0) {
263 flavor_ptr->t = object_desc_str(flavor_ptr->t, "no more ");
267 if (flavor_ptr->o_ptr->number == 1) {
271 flavor_ptr->t = object_desc_num(flavor_ptr->t, flavor_ptr->o_ptr->number);
272 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
276 static void describe_artifact_prefix_en(flavor_type *flavor_ptr)
278 flavor_ptr->s = flavor_ptr->basenm + 2;
279 if (flavor_ptr->mode & OD_OMIT_PREFIX) {
283 if (describe_prefix_en(flavor_ptr)) {
287 const auto corpse_r_idx = i2enum<MonsterRaceId>(flavor_ptr->o_ptr->pval);
288 auto is_unique_corpse = flavor_ptr->o_ptr->tval == ItemKindType::CORPSE;
289 is_unique_corpse &= monraces_info[corpse_r_idx].kind_flags.has(MonsterKindType::UNIQUE);
290 if ((flavor_ptr->known && flavor_ptr->o_ptr->is_artifact()) || is_unique_corpse) {
291 flavor_ptr->t = object_desc_str(flavor_ptr->t, "The ");
295 describe_vowel(flavor_ptr);
298 static void describe_basename_en(flavor_type *flavor_ptr)
300 flavor_ptr->s = flavor_ptr->basenm;
301 if (flavor_ptr->mode & OD_OMIT_PREFIX) {
305 if (describe_prefix_en(flavor_ptr)) {
309 if (flavor_ptr->known && flavor_ptr->o_ptr->is_artifact()) {
310 flavor_ptr->t = object_desc_str(flavor_ptr->t, "The ");
314 static void describe_artifact_body_en(flavor_type *flavor_ptr)
316 if (!flavor_ptr->known || flavor_ptr->tr_flags.has(TR_FULL_NAME) || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
320 if (flavor_ptr->o_ptr->art_name) {
321 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
322 flavor_ptr->t = object_desc_str(flavor_ptr->t, quark_str(flavor_ptr->o_ptr->art_name));
326 if (flavor_ptr->o_ptr->is_fixed_artifact()) {
327 const auto &a_ref = artifacts_info.at(flavor_ptr->o_ptr->fixed_artifact_idx);
328 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
329 flavor_ptr->t = object_desc_str(flavor_ptr->t, a_ref.name.data());
333 if (flavor_ptr->o_ptr->is_ego()) {
334 auto *e_ptr = &egos_info[flavor_ptr->o_ptr->ego_idx];
335 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
336 flavor_ptr->t = object_desc_str(flavor_ptr->t, e_ptr->name.data());
339 if (flavor_ptr->o_ptr->inscription && angband_strchr(quark_str(flavor_ptr->o_ptr->inscription), '#')) {
340 concptr str = angband_strchr(quark_str(flavor_ptr->o_ptr->inscription), '#');
341 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
342 flavor_ptr->t = object_desc_str(flavor_ptr->t, &str[1]);
349 * @param flavor_ptr アイテム表記への参照ポインタ
350 * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
352 static void describe_inscription(flavor_type *flavor_ptr)
354 for (flavor_ptr->s0 = nullptr; *flavor_ptr->s || flavor_ptr->s0;) {
355 if (!*flavor_ptr->s) {
356 flavor_ptr->s = flavor_ptr->s0 + 1;
357 flavor_ptr->s0 = nullptr;
358 } else if ((*flavor_ptr->s == '#') && !flavor_ptr->s0) {
359 flavor_ptr->s0 = flavor_ptr->s;
360 flavor_ptr->s = flavor_ptr->modstr;
361 flavor_ptr->modstr = "";
362 } else if ((*flavor_ptr->s == '%') && !flavor_ptr->s0) {
363 flavor_ptr->s0 = flavor_ptr->s;
364 flavor_ptr->s = flavor_ptr->kindname;
365 flavor_ptr->kindname = "";
370 else if (*flavor_ptr->s == '~') {
371 if (!(flavor_ptr->mode & OD_NO_PLURAL) && (flavor_ptr->o_ptr->number != 1)) {
372 char k = flavor_ptr->t[-1];
373 if ((k == 's') || (k == 'h')) {
374 *flavor_ptr->t++ = 'e';
377 *flavor_ptr->t++ = 's';
384 *flavor_ptr->t++ = *flavor_ptr->s++;
388 void describe_named_item(PlayerType *player_ptr, flavor_type *flavor_ptr)
390 check_object_known_aware(flavor_ptr);
391 switch_tval_description(flavor_ptr);
392 set_base_name(flavor_ptr);
393 flavor_ptr->t = flavor_ptr->tmp_val;
395 describe_prefix_ja(flavor_ptr);
396 describe_artifact_prefix_ja(flavor_ptr);
399 if (flavor_ptr->basenm[0] == '&') {
400 describe_artifact_prefix_en(flavor_ptr);
402 describe_basename_en(flavor_ptr);
407 if (flavor_ptr->o_ptr->is_smith() && !any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
408 flavor_ptr->t = object_desc_str(flavor_ptr->t, format("鍛冶師%sの", player_ptr->name));
411 describe_artifact_ja(flavor_ptr);
413 if (flavor_ptr->o_ptr->is_book()) {
414 // svalは0から数えているので表示用に+1している
415 flavor_ptr->t = object_desc_str(flavor_ptr->t, format("Lv%d ", flavor_ptr->o_ptr->sval + 1));
418 describe_inscription(flavor_ptr);
419 *flavor_ptr->t = '\0';
422 describe_artifact_body_ja(flavor_ptr);
424 if (flavor_ptr->o_ptr->is_smith() && !any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
425 flavor_ptr->t = object_desc_str(flavor_ptr->t, format(" of %s the Smith", player_ptr->name));
428 describe_artifact_body_en(flavor_ptr);