OSDN Git Service

[Refactor] #2628 Renamed object-type-definition.cpp/h to item-entity.cpp/h
[hengbandforosx/hengbandosx.git] / src / flavor / named-item-describer.cpp
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"
20 #ifdef JP
21 #else
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"
26 #endif
27
28 static void check_object_known_aware(flavor_type *flavor_ptr)
29 {
30     flavor_ptr->tr_flags = object_flags(flavor_ptr->o_ptr);
31     if (flavor_ptr->o_ptr->is_aware()) {
32         flavor_ptr->aware = true;
33     }
34
35     if (flavor_ptr->o_ptr->is_known()) {
36         flavor_ptr->known = true;
37     }
38
39     if (flavor_ptr->aware && ((flavor_ptr->mode & OD_NO_FLAVOR) || plain_descriptions)) {
40         flavor_ptr->flavor = false;
41     }
42
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;
47     }
48
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;
54     }
55 }
56
57 static void set_base_name(flavor_type *flavor_ptr)
58 {
59     if (!flavor_ptr->aware || flavor_ptr->tr_flags.has_not(TR_FULL_NAME)) {
60         return;
61     }
62
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;
66 }
67
68 #ifdef JP
69 static void describe_prefix_ja(flavor_type *flavor_ptr)
70 {
71     flavor_ptr->s = flavor_ptr->basenm[0] == '&' ? flavor_ptr->basenm + 2 : flavor_ptr->basenm;
72     if (flavor_ptr->mode & OD_OMIT_PREFIX) {
73         return;
74     }
75
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, "の ");
79     }
80 }
81
82 /*!
83  * @brief アーティファクトの表記処理
84  * @param アイテム表記への参照ポインタ
85  * @details 英語の場合アーティファクトは The が付くので分かるが、日本語では分からないのでマークをつける.
86  */
87 static void describe_artifact_prefix_ja(flavor_type *flavor_ptr)
88 {
89     if (!flavor_ptr->known || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
90         return;
91     }
92
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, "☆");
97     }
98 }
99
100 /*!
101  * @brief アーティファクトの説明表記
102  * @param flavor_ptr アイテム表記への参照ポインタ
103  * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
104  */
105 static void describe_artifact_ja(flavor_type *flavor_ptr)
106 {
107     if (!flavor_ptr->known || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
108         return;
109     }
110
111     if (flavor_ptr->o_ptr->art_name) {
112         concptr temp = quark_str(flavor_ptr->o_ptr->art_name);
113
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);
121         }
122
123         return;
124     }
125
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());
131         }
132
133         return;
134     }
135
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());
139     }
140 }
141
142 /*!
143  * @brief ランダムアーティファクトの表記
144  * @param flavor_ptr アイテム表記への参照ポインタ
145  * @return ランダムアーティファクトならTRUE、違うならFALSE
146  * @details ランダムアーティファクトの名前はセーブファイルに記録されるので、英語版の名前もそれらしく変換する.
147  */
148 static bool describe_random_artifact_body_ja(flavor_type *flavor_ptr)
149 {
150     if (flavor_ptr->o_ptr->art_name == 0) {
151         return false;
152     }
153
154     char temp[256];
155     int itemp;
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);
159         return true;
160     }
161
162     if (temp[0] != '\'') {
163         return true;
164     }
165
166     itemp = strlen(temp);
167     temp[itemp - 1] = 0;
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, "』");
171     return true;
172 }
173
174 static void describe_ego_body_ja(flavor_type *flavor_ptr)
175 {
176     if (!flavor_ptr->o_ptr->inscription) {
177         return;
178     }
179
180     concptr str = quark_str(flavor_ptr->o_ptr->inscription);
181     while (*str) {
182         if (iskanji(*str)) {
183             str += 2;
184             continue;
185         }
186
187         if (*str == '#') {
188             break;
189         }
190
191         str++;
192     }
193
194     if (*str == '\0') {
195         return;
196     }
197
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, "』");
202 }
203
204 /*!
205  * @brief アーティファクトのアイテム名を表記する
206  * @param flavor_ptr アイテム表記への参照ポインタ
207  * @details '『'から始まる伝説のアイテムの名前は最後に付加する
208  */
209 static void describe_artifact_body_ja(flavor_type *flavor_ptr)
210 {
211     if (!flavor_ptr->known || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
212         return;
213     }
214
215     if (describe_random_artifact_body_ja(flavor_ptr)) {
216         return;
217     }
218
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());
223         }
224
225         return;
226     }
227
228     describe_ego_body_ja(flavor_ptr);
229 }
230 #else
231
232 static void describe_vowel(flavor_type *flavor_ptr)
233 {
234     bool vowel;
235     switch (*flavor_ptr->s) {
236     case '#':
237         vowel = is_a_vowel(flavor_ptr->modstr[0]);
238         break;
239     case '%':
240         vowel = is_a_vowel(*flavor_ptr->kindname);
241         break;
242     default:
243         vowel = is_a_vowel(*flavor_ptr->s);
244         break;
245     }
246
247     if (vowel) {
248         flavor_ptr->t = object_desc_str(flavor_ptr->t, "an ");
249     } else {
250         flavor_ptr->t = object_desc_str(flavor_ptr->t, "a ");
251     }
252 }
253
254 /*!
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.
259  */
260 static bool describe_prefix_en(flavor_type *flavor_ptr)
261 {
262     if (flavor_ptr->o_ptr->number <= 0) {
263         flavor_ptr->t = object_desc_str(flavor_ptr->t, "no more ");
264         return true;
265     }
266
267     if (flavor_ptr->o_ptr->number == 1) {
268         return false;
269     }
270
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, ' ');
273     return true;
274 }
275
276 static void describe_artifact_prefix_en(flavor_type *flavor_ptr)
277 {
278     flavor_ptr->s = flavor_ptr->basenm + 2;
279     if (flavor_ptr->mode & OD_OMIT_PREFIX) {
280         return;
281     }
282
283     if (describe_prefix_en(flavor_ptr)) {
284         return;
285     }
286
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 ");
292         return;
293     }
294
295     describe_vowel(flavor_ptr);
296 }
297
298 static void describe_basename_en(flavor_type *flavor_ptr)
299 {
300     flavor_ptr->s = flavor_ptr->basenm;
301     if (flavor_ptr->mode & OD_OMIT_PREFIX) {
302         return;
303     }
304
305     if (describe_prefix_en(flavor_ptr)) {
306         return;
307     }
308
309     if (flavor_ptr->known && flavor_ptr->o_ptr->is_artifact()) {
310         flavor_ptr->t = object_desc_str(flavor_ptr->t, "The ");
311     }
312 }
313
314 static void describe_artifact_body_en(flavor_type *flavor_ptr)
315 {
316     if (!flavor_ptr->known || flavor_ptr->tr_flags.has(TR_FULL_NAME) || any_bits(flavor_ptr->mode, OD_BASE_NAME)) {
317         return;
318     }
319
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));
323         return;
324     }
325
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());
330         return;
331     }
332
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());
337     }
338
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]);
343     }
344 }
345 #endif
346
347 /*!
348  * @brief 銘を表記する
349  * @param flavor_ptr アイテム表記への参照ポインタ
350  * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
351  */
352 static void describe_inscription(flavor_type *flavor_ptr)
353 {
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 = "";
366         }
367
368 #ifdef JP
369 #else
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';
375                 }
376
377                 *flavor_ptr->t++ = 's';
378             }
379
380             flavor_ptr->s++;
381         }
382 #endif
383         else
384             *flavor_ptr->t++ = *flavor_ptr->s++;
385     }
386 }
387
388 void describe_named_item(PlayerType *player_ptr, flavor_type *flavor_ptr)
389 {
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;
394 #ifdef JP
395     describe_prefix_ja(flavor_ptr);
396     describe_artifact_prefix_ja(flavor_ptr);
397 #else
398
399     if (flavor_ptr->basenm[0] == '&') {
400         describe_artifact_prefix_en(flavor_ptr);
401     } else {
402         describe_basename_en(flavor_ptr);
403     }
404 #endif
405
406 #ifdef JP
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));
409     }
410
411     describe_artifact_ja(flavor_ptr);
412 #endif
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));
416     }
417
418     describe_inscription(flavor_ptr);
419     *flavor_ptr->t = '\0';
420
421 #ifdef JP
422     describe_artifact_body_ja(flavor_ptr);
423 #else
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));
426     }
427
428     describe_artifact_body_en(flavor_ptr);
429 #endif
430 }