OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / autopick / autopick-describer.cpp
1 /*!
2  * @brief 自動拾いの記述
3  * @date 2020/04/25
4  * @author Hourier
5  * @todo 1つ300行近い関数なので後ほど要分割
6  */
7
8 #include "autopick/autopick-describer.h"
9 #include "autopick/autopick-flags-table.h"
10 #include "autopick/autopick-key-flag-process.h"
11 #include "autopick/autopick-methods-table.h"
12 #include "autopick/autopick-util.h"
13 #include "system/angband.h"
14 #include "util/string-processor.h"
15
16 struct autopick_describer {
17     concptr str;
18     byte act;
19     concptr insc;
20     bool top;
21     int before_n;
22     concptr body_str;
23 };
24
25 #if JP
26 static void describe_autpick_jp(char *buff, const autopick_type &entry, autopick_describer *describer)
27 {
28     concptr before_str[100]{};
29     if (entry.has(FLG_COLLECTING)) {
30         before_str[describer->before_n++] = "収集中で既に持っているスロットにまとめられる";
31     }
32
33     if (entry.has(FLG_UNAWARE)) {
34         before_str[describer->before_n++] = "未鑑定でその効果も判明していない";
35     }
36
37     if (entry.has(FLG_UNIDENTIFIED)) {
38         before_str[describer->before_n++] = "未鑑定の";
39     }
40
41     if (entry.has(FLG_IDENTIFIED)) {
42         before_str[describer->before_n++] = "鑑定済みの";
43     }
44
45     if (entry.has(FLG_STAR_IDENTIFIED)) {
46         before_str[describer->before_n++] = "完全に鑑定済みの";
47     }
48
49     if (entry.has(FLG_BOOSTED)) {
50         before_str[describer->before_n++] = "ダメージダイスが通常より大きい";
51         describer->body_str = "武器";
52     }
53
54     if (entry.has(FLG_MORE_DICE)) {
55         static char more_than_desc_str[] = "___";
56         before_str[describer->before_n++] = "ダメージダイスの最大値が";
57         describer->body_str = "武器";
58
59         snprintf(more_than_desc_str, sizeof(more_than_desc_str), "%d", entry.dice);
60         before_str[describer->before_n++] = more_than_desc_str;
61         before_str[describer->before_n++] = "以上の";
62     }
63
64     if (entry.has(FLG_MORE_BONUS)) {
65         static char more_bonus_desc_str[] = "___";
66         before_str[describer->before_n++] = "修正値が(+";
67
68         snprintf(more_bonus_desc_str, sizeof(more_bonus_desc_str), "%d", entry.bonus);
69         before_str[describer->before_n++] = more_bonus_desc_str;
70         before_str[describer->before_n++] = ")以上の";
71     }
72
73     if (entry.has(FLG_WORTHLESS)) {
74         before_str[describer->before_n++] = "店で無価値と判定される";
75     }
76
77     if (entry.has(FLG_ARTIFACT)) {
78         before_str[describer->before_n++] = "アーティファクトの";
79         describer->body_str = "装備";
80     }
81
82     if (entry.has(FLG_EGO)) {
83         before_str[describer->before_n++] = "エゴアイテムの";
84         describer->body_str = "装備";
85     }
86
87     if (entry.has(FLG_GOOD)) {
88         before_str[describer->before_n++] = "上質の";
89         describer->body_str = "装備";
90     }
91
92     if (entry.has(FLG_NAMELESS)) {
93         before_str[describer->before_n++] = "エゴでもアーティファクトでもない";
94         describer->body_str = "装備";
95     }
96
97     if (entry.has(FLG_AVERAGE)) {
98         before_str[describer->before_n++] = "並の";
99         describer->body_str = "装備";
100     }
101
102     if (entry.has(FLG_RARE)) {
103         before_str[describer->before_n++] = "ドラゴン装備やカオス・ブレード等を含む珍しい";
104         describer->body_str = "装備";
105     }
106
107     if (entry.has(FLG_COMMON)) {
108         before_str[describer->before_n++] = "ありふれた(ドラゴン装備やカオス・ブレード等の珍しい物ではない)";
109         describer->body_str = "装備";
110     }
111
112     if (entry.has(FLG_WANTED)) {
113         before_str[describer->before_n++] = "ハンター事務所で賞金首とされている";
114         describer->body_str = "死体や骨";
115     }
116
117     if (entry.has(FLG_HUMAN)) {
118         before_str[describer->before_n++] = "悪魔魔法で使うための人間やヒューマノイドの";
119         describer->body_str = "死体や骨";
120     }
121
122     if (entry.has(FLG_UNIQUE)) {
123         before_str[describer->before_n++] = "ユニークモンスターの";
124         describer->body_str = "死体や骨";
125     }
126
127     if (entry.has(FLG_UNREADABLE)) {
128         before_str[describer->before_n++] = "あなたが読めない領域の";
129         describer->body_str = "魔法書";
130     }
131
132     if (entry.has(FLG_REALM1)) {
133         before_str[describer->before_n++] = "第一領域の";
134         describer->body_str = "魔法書";
135     }
136
137     if (entry.has(FLG_REALM2)) {
138         before_str[describer->before_n++] = "第二領域の";
139         describer->body_str = "魔法書";
140     }
141
142     if (entry.has(FLG_FIRST)) {
143         before_str[describer->before_n++] = "全4冊の内の1冊目の";
144         describer->body_str = "魔法書";
145     }
146
147     if (entry.has(FLG_SECOND)) {
148         before_str[describer->before_n++] = "全4冊の内の2冊目の";
149         describer->body_str = "魔法書";
150     }
151
152     if (entry.has(FLG_THIRD)) {
153         before_str[describer->before_n++] = "全4冊の内の3冊目の";
154         describer->body_str = "魔法書";
155     }
156
157     if (entry.has(FLG_FOURTH)) {
158         before_str[describer->before_n++] = "全4冊の内の4冊目の";
159         describer->body_str = "魔法書";
160     }
161
162     if (entry.has(FLG_ITEMS)) {
163         ;
164     } /* Nothing to do */
165     else if (entry.has(FLG_WEAPONS)) {
166         describer->body_str = "武器";
167     } else if (entry.has(FLG_FAVORITE_WEAPONS)) {
168         describer->body_str = "得意武器";
169     } else if (entry.has(FLG_ARMORS)) {
170         describer->body_str = "防具";
171     } else if (entry.has(FLG_MISSILES)) {
172         describer->body_str = "弾や矢やクロスボウの矢";
173     } else if (entry.has(FLG_DEVICES)) {
174         describer->body_str = "巻物や魔法棒や杖やロッド";
175     } else if (entry.has(FLG_LIGHTS)) {
176         describer->body_str = "光源用のアイテム";
177     } else if (entry.has(FLG_JUNKS)) {
178         describer->body_str = "折れた棒等のガラクタ";
179     } else if (entry.has(FLG_CORPSES)) {
180         describer->body_str = "死体や骨";
181     } else if (entry.has(FLG_SPELLBOOKS)) {
182         describer->body_str = "魔法書";
183     } else if (entry.has(FLG_HAFTED)) {
184         describer->body_str = "鈍器";
185     } else if (entry.has(FLG_SHIELDS)) {
186         describer->body_str = "盾";
187     } else if (entry.has(FLG_BOWS)) {
188         describer->body_str = "スリングや弓やクロスボウ";
189     } else if (entry.has(FLG_RINGS)) {
190         describer->body_str = "指輪";
191     } else if (entry.has(FLG_AMULETS)) {
192         describer->body_str = "アミュレット";
193     } else if (entry.has(FLG_SUITS)) {
194         describer->body_str = "鎧";
195     } else if (entry.has(FLG_CLOAKS)) {
196         describer->body_str = "クローク";
197     } else if (entry.has(FLG_HELMS)) {
198         describer->body_str = "ヘルメットや冠";
199     } else if (entry.has(FLG_GLOVES)) {
200         describer->body_str = "籠手";
201     } else if (entry.has(FLG_BOOTS)) {
202         describer->body_str = "ブーツ";
203     }
204
205     *buff = '\0';
206     if (!describer->before_n) {
207         strcat(buff, "全ての");
208     } else {
209         for (int i = 0; i < describer->before_n && before_str[i]; i++) {
210             strcat(buff, before_str[i]);
211         }
212     }
213
214     strcat(buff, describer->body_str);
215
216     if (*describer->str) {
217         if (*describer->str == '^') {
218             describer->str++;
219             describer->top = true;
220         }
221
222         strcat(buff, "で、名前が「");
223         angband_strcat(buff, describer->str, (MAX_NLEN - MAX_INSCRIPTION));
224         if (describer->top) {
225             strcat(buff, "」で始まるもの");
226         } else {
227             strcat(buff, "」を含むもの");
228         }
229     }
230
231     if (describer->insc) {
232         char tmp[MAX_INSCRIPTION + 1] = "";
233         angband_strcat(tmp, describer->insc, MAX_INSCRIPTION);
234         angband_strcat(buff, format("に「%s」", tmp), MAX_INSCRIPTION + 6);
235
236         if (str_find(describer->insc, "%%all")) {
237             strcat(buff, "(%%allは全能力を表す英字の記号で置換)");
238         } else if (str_find(describer->insc, "%all")) {
239             strcat(buff, "(%allは全能力を表す記号で置換)");
240         } else if (str_find(describer->insc, "%%")) {
241             strcat(buff, "(%%は追加能力を表す英字の記号で置換)");
242         } else if (str_find(describer->insc, "%")) {
243             strcat(buff, "(%は追加能力を表す記号で置換)");
244         }
245
246         strcat(buff, "と刻んで");
247     } else {
248         strcat(buff, "を");
249     }
250
251     if (describer->act & DONT_AUTOPICK) {
252         strcat(buff, "放置する。");
253     } else if (describer->act & DO_AUTODESTROY) {
254         strcat(buff, "破壊する。");
255     } else if (describer->act & DO_QUERY_AUTOPICK) {
256         strcat(buff, "確認の後に拾う。");
257     } else {
258         strcat(buff, "拾う。");
259     }
260
261     if (describer->act & DO_DISPLAY) {
262         if (describer->act & DONT_AUTOPICK) {
263             strcat(buff, "全体マップ('M')で'N'を押したときに表示する。");
264         } else if (describer->act & DO_AUTODESTROY) {
265             strcat(buff, "全体マップ('M')で'K'を押したときに表示する。");
266         } else {
267             strcat(buff, "全体マップ('M')で'M'を押したときに表示する。");
268         }
269     } else {
270         strcat(buff, "全体マップには表示しない。");
271     }
272 }
273 #else
274
275 void describe_autopick_en(char *buff, const autopick_type &entry, autopick_describer *describer)
276 {
277     concptr before_str[20]{};
278     concptr after_str[20]{};
279     concptr which_str[20]{};
280     concptr whose_str[20]{};
281     concptr whose_arg_str[20]{};
282     char arg_str[2][24]{};
283     int after_n = 0, which_n = 0, whose_n = 0, arg_n = 0;
284     if (entry.has(FLG_COLLECTING)) {
285         which_str[which_n++] = "can be absorbed into an existing inventory list slot";
286     }
287
288     if (entry.has(FLG_UNAWARE)) {
289         before_str[describer->before_n++] = "unidentified";
290         whose_str[whose_n] = "basic abilities are not known";
291         whose_arg_str[whose_n] = "";
292         ++whose_n;
293     }
294
295     if (entry.has(FLG_UNIDENTIFIED)) {
296         before_str[describer->before_n++] = "unidentified";
297     }
298
299     if (entry.has(FLG_IDENTIFIED)) {
300         before_str[describer->before_n++] = "identified";
301     }
302
303     if (entry.has(FLG_STAR_IDENTIFIED)) {
304         before_str[describer->before_n++] = "fully identified";
305     }
306
307     if (entry.has(FLG_RARE)) {
308         before_str[describer->before_n++] = "very rare";
309         after_str[after_n++] = "such as Dragon armor, Blades of Chaos, etc.";
310     }
311
312     if (entry.has(FLG_COMMON)) {
313         before_str[describer->before_n++] = "relatively common";
314         after_str[after_n++] = "compared to very rare Dragon armor, Blades of Chaos, etc.";
315     }
316
317     if (entry.has(FLG_WORTHLESS)) {
318         before_str[describer->before_n++] = "worthless";
319         which_str[which_n++] = "can not be sold at stores";
320     }
321
322     if (entry.has(FLG_ARTIFACT)) {
323         before_str[describer->before_n++] = "artifact";
324     }
325
326     if (entry.has(FLG_EGO)) {
327         before_str[describer->before_n++] = "ego";
328     }
329
330     if (entry.has(FLG_GOOD)) {
331         which_str[which_n++] = "are of good quality";
332     }
333
334     if (entry.has(FLG_NAMELESS)) {
335         which_str[which_n++] = "are neither ego items nor artifacts";
336     }
337
338     if (entry.has(FLG_AVERAGE)) {
339         which_str[which_n++] = "are of average quality";
340     }
341
342     if (entry.has(FLG_BOOSTED)) {
343         describer->body_str = "weapons";
344         whose_str[whose_n] = "damage dice is bigger than normal";
345         whose_arg_str[whose_n] = "";
346         ++whose_n;
347     }
348
349     if (entry.has(FLG_MORE_DICE)) {
350         describer->body_str = "weapons";
351         whose_str[whose_n] = "maximum damage from dice is bigger than ";
352         if (arg_n < (int)(sizeof(arg_str) / sizeof(arg_str[0]))) {
353             snprintf(arg_str[arg_n], sizeof(arg_str[arg_n]), "%d", entry.dice);
354             whose_arg_str[whose_n] = arg_str[arg_n];
355             ++arg_n;
356         } else {
357             whose_arg_str[whose_n] = "garbled";
358         }
359         ++whose_n;
360     }
361
362     if (entry.has(FLG_MORE_BONUS)) {
363         whose_str[whose_n] = "magical bonuses are bigger than (+";
364         if (arg_n < (int)(sizeof(arg_str) / sizeof(arg_str[0]))) {
365             snprintf(arg_str[arg_n], sizeof(arg_str[arg_n]), "%d)", entry.bonus);
366             whose_arg_str[whose_n] = arg_str[arg_n];
367             ++arg_n;
368         } else {
369             whose_arg_str[whose_n] = "garbled)";
370         }
371         ++whose_n;
372     }
373
374     if (entry.has(FLG_WANTED)) {
375         describer->body_str = "corpses or skeletons";
376         which_str[which_n++] = "are wanted at the Hunter's Office";
377     }
378
379     if (entry.has(FLG_HUMAN)) {
380         before_str[describer->before_n++] = "humanoid";
381         describer->body_str = "corpses or skeletons";
382         which_str[which_n++] = "can be used for Daemon magic";
383     }
384
385     if (entry.has(FLG_UNIQUE)) {
386         before_str[describer->before_n++] = "unique monsters'";
387         describer->body_str = "corpses or skeletons";
388     }
389
390     if (entry.has(FLG_UNREADABLE)) {
391         describer->body_str = "spellbooks";
392         after_str[after_n++] = "of different realms from yours";
393     }
394
395     if (entry.has(FLG_REALM1)) {
396         describer->body_str = "spellbooks";
397         after_str[after_n++] = "of your first realm";
398     }
399
400     if (entry.has(FLG_REALM2)) {
401         describer->body_str = "spellbooks";
402         after_str[after_n++] = "of your second realm";
403     }
404
405     if (entry.has(FLG_FIRST)) {
406         before_str[describer->before_n++] = "first one of four";
407         describer->body_str = "spellbooks";
408     }
409
410     if (entry.has(FLG_SECOND)) {
411         before_str[describer->before_n++] = "second one of four";
412         describer->body_str = "spellbooks";
413     }
414
415     if (entry.has(FLG_THIRD)) {
416         before_str[describer->before_n++] = "third one of four";
417         describer->body_str = "spellbooks";
418     }
419
420     if (entry.has(FLG_FOURTH)) {
421         before_str[describer->before_n++] = "fourth one of four";
422         describer->body_str = "spellbooks";
423     }
424
425     if (entry.has(FLG_ITEMS)) {
426         ;
427     } /* Nothing to do */
428     else if (entry.has(FLG_WEAPONS)) {
429         describer->body_str = "weapons";
430     } else if (entry.has(FLG_FAVORITE_WEAPONS)) {
431         describer->body_str = "favorite weapons";
432     } else if (entry.has(FLG_ARMORS)) {
433         describer->body_str = "pieces of armor";
434     } else if (entry.has(FLG_MISSILES)) {
435         describer->body_str = "shots, arrows or crossbow bolts";
436     } else if (entry.has(FLG_DEVICES)) {
437         describer->body_str = "scrolls, wands, staffs or rods";
438     } else if (entry.has(FLG_LIGHTS)) {
439         describer->body_str = "light sources";
440     } else if (entry.has(FLG_JUNKS)) {
441         describer->body_str = "pieces of junk such as broken sticks";
442     } else if (entry.has(FLG_CORPSES)) {
443         describer->body_str = "corpses or skeletons";
444     } else if (entry.has(FLG_SPELLBOOKS)) {
445         describer->body_str = "spellbooks";
446     } else if (entry.has(FLG_HAFTED)) {
447         describer->body_str = "hafted weapons";
448     } else if (entry.has(FLG_SHIELDS)) {
449         describer->body_str = "shields";
450     } else if (entry.has(FLG_BOWS)) {
451         describer->body_str = "slings, bows or crossbows";
452     } else if (entry.has(FLG_RINGS)) {
453         describer->body_str = "rings";
454     } else if (entry.has(FLG_AMULETS)) {
455         describer->body_str = "amulets";
456     } else if (entry.has(FLG_SUITS)) {
457         describer->body_str = "pieces of body armor";
458     } else if (entry.has(FLG_CLOAKS)) {
459         describer->body_str = "cloaks";
460     } else if (entry.has(FLG_HELMS)) {
461         describer->body_str = "helms or crowns";
462     } else if (entry.has(FLG_GLOVES)) {
463         describer->body_str = "gloves";
464     } else if (entry.has(FLG_BOOTS)) {
465         describer->body_str = "boots";
466     }
467
468     if (*describer->str) {
469         if (*describer->str == '^') {
470             describer->str++;
471             describer->top = true;
472             whose_str[whose_n] = "names begin with \"";
473             whose_arg_str[whose_n] = "";
474             ++whose_n;
475         } else {
476             which_str[which_n++] = "have \"";
477         }
478     }
479
480     if (describer->act & DONT_AUTOPICK) {
481         strcpy(buff, "Leave on floor ");
482     } else if (describer->act & DO_AUTODESTROY) {
483         strcpy(buff, "Destroy ");
484     } else if (describer->act & DO_QUERY_AUTOPICK) {
485         strcpy(buff, "Ask to pick up ");
486     } else {
487         strcpy(buff, "Pickup ");
488     }
489
490     if (describer->insc) {
491         strncat(buff, format("and inscribe \"%s\"", describer->insc).data(), 80);
492
493         if (angband_strstr(describer->insc, "%all")) {
494             strcat(buff, ", replacing %all with code string representing all abilities,");
495         } else if (angband_strstr(describer->insc, "%")) {
496             strcat(buff, ", replacing % with code string representing extra random abilities,");
497         }
498
499         strcat(buff, " on ");
500     }
501
502     if (!describer->before_n) {
503         strcat(buff, "all ");
504     } else {
505         for (int i = 0; i < describer->before_n && before_str[i]; i++) {
506             strcat(buff, before_str[i]);
507             strcat(buff, " ");
508         }
509     }
510
511     strcat(buff, describer->body_str);
512     for (int i = 0; i < after_n && after_str[i]; i++) {
513         strcat(buff, " ");
514         strcat(buff, after_str[i]);
515     }
516
517     for (int i = 0; i < whose_n && whose_str[i]; i++) {
518         if (i == 0) {
519             strcat(buff, " whose ");
520         } else {
521             strcat(buff, ", and ");
522         }
523
524         strcat(buff, whose_str[i]);
525         strcat(buff, whose_arg_str[i]);
526     }
527
528     if (*describer->str && describer->top) {
529         strcat(buff, describer->str);
530         strcat(buff, "\"");
531     }
532
533     if (whose_n && which_n) {
534         strcat(buff, ", and ");
535     }
536
537     for (int i = 0; i < which_n && which_str[i]; i++) {
538         if (i == 0) {
539             strcat(buff, " which ");
540         } else {
541             strcat(buff, ", and ");
542         }
543
544         strcat(buff, which_str[i]);
545     }
546
547     if (*describer->str && !describer->top) {
548         strncat(buff, describer->str, 80);
549         strcat(buff, "\" as part of their names");
550     }
551
552     strcat(buff, ".");
553
554     if (describer->act & DO_DISPLAY) {
555         if (describer->act & DONT_AUTOPICK) {
556             strcat(buff, "  Display these items when you press the N key in the full 'M'ap.");
557         } else if (describer->act & DO_AUTODESTROY) {
558             strcat(buff, "  Display these items when you press the K key in the full 'M'ap.");
559         } else {
560             strcat(buff, "  Display these items when you press the M key in the full 'M'ap.");
561         }
562     } else {
563         strcat(buff, " Not displayed in the full map.");
564     }
565 }
566 #endif
567
568 /*!
569  * @brief Describe which kind of object is Auto-picked/destroyed
570  */
571 void describe_autopick(char *buff, const autopick_type &entry)
572 {
573     //! @note autopick_describer::str は non-nullable、autopick_describer::insc は nullable という制約がある
574     autopick_describer describer;
575     describer.str = entry.name.data();
576     describer.act = entry.action;
577     describer.insc = entry.insc.empty() ? nullptr : entry.insc.data();
578     describer.top = false;
579     describer.before_n = 0;
580     describer.body_str = _("アイテム", "items");
581 #ifdef JP
582     describe_autpick_jp(buff, entry, &describer);
583 #else
584     describe_autopick_en(buff, entry, &describer);
585 #endif
586 }