1 #include "flavor/named-item-describer.h"
2 #include "flavor/flavor-util.h"
3 #include "flavor/object-flavor-types.h"
4 #include "flavor/tval-description-switcher.h"
5 #include "game-option/text-display-options.h"
6 #include "locale/english.h"
7 #include "mind/mind-weaponsmith.h"
8 #include "object-enchant/object-ego.h"
9 #include "object-enchant/special-object-flags.h"
10 #include "object-enchant/tr-types.h"
11 #include "object/object-flags.h"
12 #include "perception/object-perception.h"
13 #include "system/artifact-type-definition.h"
14 #include "system/player-type-definition.h"
15 #include "util/bit-flags-calculator.h"
16 #include "util/quarks.h"
17 #include "util/string-processor.h"
20 #include "monster-race/monster-race.h"
21 #include "monster-race/race-flags1.h"
22 #include "object/tval-types.h"
23 #include "system/monster-race-definition.h"
26 static void check_object_known_aware(flavor_type *flavor_ptr)
28 flavor_ptr->tr_flags = object_flags(flavor_ptr->o_ptr);
29 if (flavor_ptr->o_ptr->is_aware()) {
30 flavor_ptr->aware = true;
33 if (flavor_ptr->o_ptr->is_known()) {
34 flavor_ptr->known = true;
37 if (flavor_ptr->aware && ((flavor_ptr->mode & OD_NO_FLAVOR) || plain_descriptions)) {
38 flavor_ptr->flavor = false;
41 if ((flavor_ptr->mode & OD_STORE) || (flavor_ptr->o_ptr->ident & IDENT_STORE)) {
42 flavor_ptr->flavor = false;
43 flavor_ptr->aware = true;
44 flavor_ptr->known = true;
47 if (flavor_ptr->mode & OD_FORCE_FLAVOR) {
48 flavor_ptr->aware = false;
49 flavor_ptr->flavor = true;
50 flavor_ptr->known = false;
51 flavor_ptr->flavor_k_ptr = flavor_ptr->k_ptr;
55 static void set_base_name(flavor_type *flavor_ptr)
57 if (!flavor_ptr->aware || flavor_ptr->tr_flags.has_not(TR_FULL_NAME)) {
61 flavor_ptr->basenm = (flavor_ptr->known && (flavor_ptr->o_ptr->fixed_artifact_idx != 0)) ? a_info[flavor_ptr->o_ptr->fixed_artifact_idx].name.c_str() : flavor_ptr->kindname;
65 static void describe_prefix_ja(flavor_type *flavor_ptr)
67 flavor_ptr->s = flavor_ptr->basenm[0] == '&' ? flavor_ptr->basenm + 2 : flavor_ptr->basenm;
68 if (flavor_ptr->mode & OD_OMIT_PREFIX) {
72 if (flavor_ptr->o_ptr->number > 1) {
73 flavor_ptr->t = object_desc_count_japanese(flavor_ptr->t, flavor_ptr->o_ptr);
74 flavor_ptr->t = object_desc_str(flavor_ptr->t, "の ");
79 * @brief アーティファクトの表記処理
80 * @param アイテム表記への参照ポインタ
81 * @details 英語の場合アーティファクトは The が付くので分かるが、日本語では分からないのでマークをつける.
83 static void describe_artifact_prefix_ja(flavor_type *flavor_ptr)
85 if (!flavor_ptr->known) {
89 if (flavor_ptr->o_ptr->is_fixed_artifact()) {
90 flavor_ptr->t = object_desc_str(flavor_ptr->t, "★");
91 } else if (flavor_ptr->o_ptr->art_name) {
92 flavor_ptr->t = object_desc_str(flavor_ptr->t, "☆");
97 * @brief アーティファクトの説明表記
98 * @param flavor_ptr アイテム表記への参照ポインタ
99 * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
101 static void describe_artifact_ja(flavor_type *flavor_ptr)
103 if (!flavor_ptr->known) {
107 if (flavor_ptr->o_ptr->art_name) {
108 concptr temp = quark_str(flavor_ptr->o_ptr->art_name);
110 /* '『' から始まらない伝説のアイテムの名前は最初に付加する */
111 /* 英語版のセーブファイルから来た 'of XXX' は,「XXXの」と表示する */
112 if (strncmp(temp, "of ", 3) == 0) {
113 flavor_ptr->t = object_desc_str(flavor_ptr->t, &temp[3]);
114 flavor_ptr->t = object_desc_str(flavor_ptr->t, "の");
115 } else if ((strncmp(temp, "『", 2) != 0) && (strncmp(temp, "《", 2) != 0) && (temp[0] != '\'')) {
116 flavor_ptr->t = object_desc_str(flavor_ptr->t, temp);
122 if (flavor_ptr->o_ptr->fixed_artifact_idx && flavor_ptr->tr_flags.has_not(TR_FULL_NAME)) {
123 auto *a_ptr = &a_info[flavor_ptr->o_ptr->fixed_artifact_idx];
124 /* '『' から始まらない伝説のアイテムの名前は最初に付加する */
125 if (a_ptr->name.find("『", 0, 2) != 0) {
126 flavor_ptr->t = object_desc_str(flavor_ptr->t, a_ptr->name.c_str());
132 if (flavor_ptr->o_ptr->is_ego()) {
133 auto *e_ptr = &e_info[flavor_ptr->o_ptr->ego_idx];
134 flavor_ptr->t = object_desc_str(flavor_ptr->t, e_ptr->name.c_str());
139 * @brief ランダムアーティファクトの表記
140 * @param flavor_ptr アイテム表記への参照ポインタ
141 * @return ランダムアーティファクトならTRUE、違うならFALSE
142 * @details ランダムアーティファクトの名前はセーブファイルに記録されるので、英語版の名前もそれらしく変換する.
144 static bool describe_random_artifact_body_ja(flavor_type *flavor_ptr)
146 if (flavor_ptr->o_ptr->art_name == 0) {
152 strcpy(temp, quark_str(flavor_ptr->o_ptr->art_name));
153 if (strncmp(temp, "『", 2) == 0 || strncmp(temp, "《", 2) == 0) {
154 flavor_ptr->t = object_desc_str(flavor_ptr->t, temp);
158 if (temp[0] != '\'') {
162 itemp = strlen(temp);
164 flavor_ptr->t = object_desc_str(flavor_ptr->t, "『");
165 flavor_ptr->t = object_desc_str(flavor_ptr->t, &temp[1]);
166 flavor_ptr->t = object_desc_str(flavor_ptr->t, "』");
170 static void describe_ego_body_ja(flavor_type *flavor_ptr)
172 if (!flavor_ptr->o_ptr->inscription) {
176 concptr str = quark_str(flavor_ptr->o_ptr->inscription);
194 concptr str_aux = angband_strchr(quark_str(flavor_ptr->o_ptr->inscription), '#');
195 flavor_ptr->t = object_desc_str(flavor_ptr->t, "『");
196 flavor_ptr->t = object_desc_str(flavor_ptr->t, &str_aux[1]);
197 flavor_ptr->t = object_desc_str(flavor_ptr->t, "』");
201 * @brief アーティファクトのアイテム名を表記する
202 * @param flavor_ptr アイテム表記への参照ポインタ
203 * @details '『'から始まる伝説のアイテムの名前は最後に付加する
205 static void describe_artifact_body_ja(flavor_type *flavor_ptr)
207 if (!flavor_ptr->known) {
211 if (describe_random_artifact_body_ja(flavor_ptr)) {
215 if (flavor_ptr->o_ptr->is_fixed_artifact()) {
216 auto *a_ptr = &a_info[flavor_ptr->o_ptr->fixed_artifact_idx];
217 if (a_ptr->name.find("『", 0, 2) == 0) {
218 flavor_ptr->t = object_desc_str(flavor_ptr->t, a_ptr->name.c_str());
224 describe_ego_body_ja(flavor_ptr);
228 static void describe_vowel(flavor_type *flavor_ptr)
231 switch (*flavor_ptr->s) {
233 vowel = is_a_vowel(flavor_ptr->modstr[0]);
236 vowel = is_a_vowel(*flavor_ptr->kindname);
239 vowel = is_a_vowel(*flavor_ptr->s);
244 flavor_ptr->t = object_desc_str(flavor_ptr->t, "an ");
246 flavor_ptr->t = object_desc_str(flavor_ptr->t, "a ");
251 * @brief 0個、1個、2個以上の時に個数を書き分ける処理 / Process to write the number when there are 0, 1, or 2 or more.
252 * @param flavor_ptr アイテム表記への参照ポインタ / Reference pointer to item's flavor
253 * @return 1個ならFALSE、0または2個以上ならTRUE / If the number of items is 1, then FALE is returned, and if 0 or 2 or more, then TRUE is returned
254 * @details 1個なら後続処理実行 / If the number of items is 1, then the continuous process will be run.
256 static bool describe_prefix_en(flavor_type *flavor_ptr)
258 if (flavor_ptr->o_ptr->number <= 0) {
259 flavor_ptr->t = object_desc_str(flavor_ptr->t, "no more ");
263 if (flavor_ptr->o_ptr->number == 1) {
267 flavor_ptr->t = object_desc_num(flavor_ptr->t, flavor_ptr->o_ptr->number);
268 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
272 static void describe_artifact_prefix_en(flavor_type *flavor_ptr)
274 flavor_ptr->s = flavor_ptr->basenm + 2;
275 if (flavor_ptr->mode & OD_OMIT_PREFIX) {
279 if (describe_prefix_en(flavor_ptr)) {
283 const auto corpse_r_idx = i2enum<MonsterRaceId>(flavor_ptr->o_ptr->pval);
284 if ((flavor_ptr->known && flavor_ptr->o_ptr->is_artifact()) || ((flavor_ptr->o_ptr->tval == ItemKindType::CORPSE) && r_info[corpse_r_idx].kind_flags.has(MonsterKindType::UNIQUE))) {
285 flavor_ptr->t = object_desc_str(flavor_ptr->t, "The ");
289 describe_vowel(flavor_ptr);
292 static void describe_basename_en(flavor_type *flavor_ptr)
294 flavor_ptr->s = flavor_ptr->basenm;
295 if (flavor_ptr->mode & OD_OMIT_PREFIX) {
299 if (describe_prefix_en(flavor_ptr)) {
303 if (flavor_ptr->known && flavor_ptr->o_ptr->is_artifact()) {
304 flavor_ptr->t = object_desc_str(flavor_ptr->t, "The ");
308 static void describe_artifact_body_en(flavor_type *flavor_ptr)
310 if (!flavor_ptr->known || flavor_ptr->tr_flags.has(TR_FULL_NAME)) {
314 if (flavor_ptr->o_ptr->art_name) {
315 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
316 flavor_ptr->t = object_desc_str(flavor_ptr->t, quark_str(flavor_ptr->o_ptr->art_name));
320 if (flavor_ptr->o_ptr->is_fixed_artifact()) {
321 auto *a_ptr = &a_info[flavor_ptr->o_ptr->fixed_artifact_idx];
322 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
323 flavor_ptr->t = object_desc_str(flavor_ptr->t, a_ptr->name.c_str());
327 if (flavor_ptr->o_ptr->is_ego()) {
328 auto *e_ptr = &e_info[flavor_ptr->o_ptr->ego_idx];
329 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
330 flavor_ptr->t = object_desc_str(flavor_ptr->t, e_ptr->name.c_str());
333 if (flavor_ptr->o_ptr->inscription && angband_strchr(quark_str(flavor_ptr->o_ptr->inscription), '#')) {
334 concptr str = angband_strchr(quark_str(flavor_ptr->o_ptr->inscription), '#');
335 flavor_ptr->t = object_desc_chr(flavor_ptr->t, ' ');
336 flavor_ptr->t = object_desc_str(flavor_ptr->t, &str[1]);
343 * @param flavor_ptr アイテム表記への参照ポインタ
344 * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
346 static void describe_inscription(flavor_type *flavor_ptr)
348 for (flavor_ptr->s0 = nullptr; *flavor_ptr->s || flavor_ptr->s0;) {
349 if (!*flavor_ptr->s) {
350 flavor_ptr->s = flavor_ptr->s0 + 1;
351 flavor_ptr->s0 = nullptr;
352 } else if ((*flavor_ptr->s == '#') && !flavor_ptr->s0) {
353 flavor_ptr->s0 = flavor_ptr->s;
354 flavor_ptr->s = flavor_ptr->modstr;
355 flavor_ptr->modstr = "";
356 } else if ((*flavor_ptr->s == '%') && !flavor_ptr->s0) {
357 flavor_ptr->s0 = flavor_ptr->s;
358 flavor_ptr->s = flavor_ptr->kindname;
359 flavor_ptr->kindname = "";
364 else if (*flavor_ptr->s == '~') {
365 if (!(flavor_ptr->mode & OD_NO_PLURAL) && (flavor_ptr->o_ptr->number != 1)) {
366 char k = flavor_ptr->t[-1];
367 if ((k == 's') || (k == 'h')) {
368 *flavor_ptr->t++ = 'e';
371 *flavor_ptr->t++ = 's';
378 *flavor_ptr->t++ = *flavor_ptr->s++;
382 void describe_named_item(PlayerType *player_ptr, flavor_type *flavor_ptr)
384 check_object_known_aware(flavor_ptr);
385 switch_tval_description(flavor_ptr);
386 set_base_name(flavor_ptr);
387 flavor_ptr->t = flavor_ptr->tmp_val;
389 describe_prefix_ja(flavor_ptr);
390 describe_artifact_prefix_ja(flavor_ptr);
393 if (flavor_ptr->basenm[0] == '&') {
394 describe_artifact_prefix_en(flavor_ptr);
396 describe_basename_en(flavor_ptr);
401 if (flavor_ptr->o_ptr->is_smith()) {
402 flavor_ptr->t = object_desc_str(flavor_ptr->t, format("鍛冶師%sの", player_ptr->name));
405 describe_artifact_ja(flavor_ptr);
408 describe_inscription(flavor_ptr);
409 *flavor_ptr->t = '\0';
412 describe_artifact_body_ja(flavor_ptr);
414 if (flavor_ptr->o_ptr->is_smith()) {
415 flavor_ptr->t = object_desc_str(flavor_ptr->t, format(" of %s the Smith", player_ptr->name));
418 describe_artifact_body_en(flavor_ptr);