OSDN Git Service

fe384d2eb3b10b2b3cdd04807f27f13c503f2b77
[hengbandforosx/hengbandosx.git] / src / flavor / named-item-describer.cpp
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"
18 #ifdef JP
19 #else
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"
24 #endif
25
26 static void check_object_known_aware(flavor_type *flavor_ptr)
27 {
28     flavor_ptr->tr_flags = object_flags(flavor_ptr->o_ptr);
29     if (flavor_ptr->o_ptr->is_aware()) {
30         flavor_ptr->aware = true;
31     }
32
33     if (flavor_ptr->o_ptr->is_known()) {
34         flavor_ptr->known = true;
35     }
36
37     if (flavor_ptr->aware && ((flavor_ptr->mode & OD_NO_FLAVOR) || plain_descriptions)) {
38         flavor_ptr->flavor = false;
39     }
40
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;
45     }
46
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;
52     }
53 }
54
55 static void set_base_name(flavor_type *flavor_ptr)
56 {
57     if (!flavor_ptr->aware || flavor_ptr->tr_flags.has_not(TR_FULL_NAME)) {
58         return;
59     }
60
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;
62 }
63
64 #ifdef JP
65 static void describe_prefix_ja(flavor_type *flavor_ptr)
66 {
67     flavor_ptr->s = flavor_ptr->basenm[0] == '&' ? flavor_ptr->basenm + 2 : flavor_ptr->basenm;
68     if (flavor_ptr->mode & OD_OMIT_PREFIX) {
69         return;
70     }
71
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, "の ");
75     }
76 }
77
78 /*!
79  * @brief アーティファクトの表記処理
80  * @param アイテム表記への参照ポインタ
81  * @details 英語の場合アーティファクトは The が付くので分かるが、日本語では分からないのでマークをつける.
82  */
83 static void describe_artifact_prefix_ja(flavor_type *flavor_ptr)
84 {
85     if (!flavor_ptr->known) {
86         return;
87     }
88
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, "☆");
93     }
94 }
95
96 /*!
97  * @brief アーティファクトの説明表記
98  * @param flavor_ptr アイテム表記への参照ポインタ
99  * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
100  */
101 static void describe_artifact_ja(flavor_type *flavor_ptr)
102 {
103     if (!flavor_ptr->known) {
104         return;
105     }
106
107     if (flavor_ptr->o_ptr->art_name) {
108         concptr temp = quark_str(flavor_ptr->o_ptr->art_name);
109
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);
117         }
118
119         return;
120     }
121
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());
127         }
128
129         return;
130     }
131
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());
135     }
136 }
137
138 /*!
139  * @brief ランダムアーティファクトの表記
140  * @param flavor_ptr アイテム表記への参照ポインタ
141  * @return ランダムアーティファクトならTRUE、違うならFALSE
142  * @details ランダムアーティファクトの名前はセーブファイルに記録されるので、英語版の名前もそれらしく変換する.
143  */
144 static bool describe_random_artifact_body_ja(flavor_type *flavor_ptr)
145 {
146     if (flavor_ptr->o_ptr->art_name == 0) {
147         return false;
148     }
149
150     char temp[256];
151     int itemp;
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);
155         return true;
156     }
157
158     if (temp[0] != '\'') {
159         return true;
160     }
161
162     itemp = strlen(temp);
163     temp[itemp - 1] = 0;
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, "』");
167     return true;
168 }
169
170 static void describe_ego_body_ja(flavor_type *flavor_ptr)
171 {
172     if (!flavor_ptr->o_ptr->inscription) {
173         return;
174     }
175
176     concptr str = quark_str(flavor_ptr->o_ptr->inscription);
177     while (*str) {
178         if (iskanji(*str)) {
179             str += 2;
180             continue;
181         }
182
183         if (*str == '#') {
184             break;
185         }
186
187         str++;
188     }
189
190     if (*str == '\0') {
191         return;
192     }
193
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, "』");
198 }
199
200 /*!
201  * @brief アーティファクトのアイテム名を表記する
202  * @param flavor_ptr アイテム表記への参照ポインタ
203  * @details '『'から始まる伝説のアイテムの名前は最後に付加する
204  */
205 static void describe_artifact_body_ja(flavor_type *flavor_ptr)
206 {
207     if (!flavor_ptr->known) {
208         return;
209     }
210
211     if (describe_random_artifact_body_ja(flavor_ptr)) {
212         return;
213     }
214
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());
219         }
220
221         return;
222     }
223
224     describe_ego_body_ja(flavor_ptr);
225 }
226 #else
227
228 static void describe_vowel(flavor_type *flavor_ptr)
229 {
230     bool vowel;
231     switch (*flavor_ptr->s) {
232     case '#':
233         vowel = is_a_vowel(flavor_ptr->modstr[0]);
234         break;
235     case '%':
236         vowel = is_a_vowel(*flavor_ptr->kindname);
237         break;
238     default:
239         vowel = is_a_vowel(*flavor_ptr->s);
240         break;
241     }
242
243     if (vowel) {
244         flavor_ptr->t = object_desc_str(flavor_ptr->t, "an ");
245     } else {
246         flavor_ptr->t = object_desc_str(flavor_ptr->t, "a ");
247     }
248 }
249
250 /*!
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.
255  */
256 static bool describe_prefix_en(flavor_type *flavor_ptr)
257 {
258     if (flavor_ptr->o_ptr->number <= 0) {
259         flavor_ptr->t = object_desc_str(flavor_ptr->t, "no more ");
260         return true;
261     }
262
263     if (flavor_ptr->o_ptr->number == 1) {
264         return false;
265     }
266
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, ' ');
269     return true;
270 }
271
272 static void describe_artifact_prefix_en(flavor_type *flavor_ptr)
273 {
274     flavor_ptr->s = flavor_ptr->basenm + 2;
275     if (flavor_ptr->mode & OD_OMIT_PREFIX) {
276         return;
277     }
278
279     if (describe_prefix_en(flavor_ptr)) {
280         return;
281     }
282
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 ");
286         return;
287     }
288
289     describe_vowel(flavor_ptr);
290 }
291
292 static void describe_basename_en(flavor_type *flavor_ptr)
293 {
294     flavor_ptr->s = flavor_ptr->basenm;
295     if (flavor_ptr->mode & OD_OMIT_PREFIX) {
296         return;
297     }
298
299     if (describe_prefix_en(flavor_ptr)) {
300         return;
301     }
302
303     if (flavor_ptr->known && flavor_ptr->o_ptr->is_artifact()) {
304         flavor_ptr->t = object_desc_str(flavor_ptr->t, "The ");
305     }
306 }
307
308 static void describe_artifact_body_en(flavor_type *flavor_ptr)
309 {
310     if (!flavor_ptr->known || flavor_ptr->tr_flags.has(TR_FULL_NAME)) {
311         return;
312     }
313
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));
317         return;
318     }
319
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());
324         return;
325     }
326
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());
331     }
332
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]);
337     }
338 }
339 #endif
340
341 /*!
342  * @brief 銘を表記する
343  * @param flavor_ptr アイテム表記への参照ポインタ
344  * @details ランダムアーティファクト、固定アーティファクト、エゴの順に評価する
345  */
346 static void describe_inscription(flavor_type *flavor_ptr)
347 {
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 = "";
360         }
361
362 #ifdef JP
363 #else
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';
369                 }
370
371                 *flavor_ptr->t++ = 's';
372             }
373
374             flavor_ptr->s++;
375         }
376 #endif
377         else
378             *flavor_ptr->t++ = *flavor_ptr->s++;
379     }
380 }
381
382 void describe_named_item(PlayerType *player_ptr, flavor_type *flavor_ptr)
383 {
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;
388 #ifdef JP
389     describe_prefix_ja(flavor_ptr);
390     describe_artifact_prefix_ja(flavor_ptr);
391 #else
392
393     if (flavor_ptr->basenm[0] == '&') {
394         describe_artifact_prefix_en(flavor_ptr);
395     } else {
396         describe_basename_en(flavor_ptr);
397     }
398 #endif
399
400 #ifdef JP
401     if (flavor_ptr->o_ptr->is_smith()) {
402         flavor_ptr->t = object_desc_str(flavor_ptr->t, format("鍛冶師%sの", player_ptr->name));
403     }
404
405     describe_artifact_ja(flavor_ptr);
406 #endif
407
408     describe_inscription(flavor_ptr);
409     *flavor_ptr->t = '\0';
410
411 #ifdef JP
412     describe_artifact_body_ja(flavor_ptr);
413 #else
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));
416     }
417
418     describe_artifact_body_en(flavor_ptr);
419 #endif
420 }