OSDN Git Service

[Backout] モンスターの素早さに関するフレーバーを元に戻した / Reverted flavor texts about the speed of monsters
[hengbandforosx/hengbandosx.git] / src / wizard1.c
1 /*!
2  *  @file wizard1.c
3  *  @brief ウィザードモードの処理(スポイラー出力中心) / Spoiler generation -BEN-
4  *  @date 2014/02/17
5  *  @author
6  * Copyright (c) 1997 Ben Harrison, and others
7  * This software may be copied and distributed for educational, research,
8  * and not for profit purposes provided that this copyright and statement
9  * are included in all such copies.  Other copyrights may also apply.
10  * 2013 Deskull rearranged comment for Doxygen.
11  */
12
13 #include "angband.h"
14 #include "util.h"
15 #include "gameterm.h"
16
17 #include "core/angband-version.h"
18 #include "artifact.h"
19 #include "sort.h"
20 #include "market/store.h"
21 #include "market/store-util.h"
22 #include "monster.h"
23 #include "object-flavor.h"
24 #include "object-hook.h"
25 #include "object-ego.h"
26 #include "object/object-kind.h"
27 #include "floor-town.h"
28 #include "files.h"
29
30  /*
31   * The spoiler file being created
32   */
33 static FILE *fff = NULL;
34
35 /*!
36  * @brief シンボル職の記述名を返す /
37  * Extract a textual representation of an attribute
38  * @param r_ptr モンスター種族の構造体ポインタ
39  * @return シンボル職の記述名
40  */
41 static concptr attr_to_text(monster_race *r_ptr)
42 {
43         if (r_ptr->flags1 & RF1_ATTR_CLEAR)    return _("透明な", "Clear");
44         if (r_ptr->flags1 & RF1_ATTR_MULTI)    return _("万色の", "Multi");
45         if (r_ptr->flags1 & RF1_ATTR_SEMIRAND) return _("準ランダムな", "S.Rand");
46
47         switch (r_ptr->d_attr)
48         {
49         case TERM_DARK:    return _("黒い", "Dark");
50         case TERM_WHITE:   return _("白い", "White");
51         case TERM_SLATE:   return _("青灰色の", "Slate");
52         case TERM_ORANGE:  return _("オレンジの", "Orange");
53         case TERM_RED:     return _("赤い", "Red");
54         case TERM_GREEN:   return _("緑の", "Green");
55         case TERM_BLUE:    return _("青い", "Blue");
56         case TERM_UMBER:   return _("琥珀色の", "Umber");
57         case TERM_L_DARK:  return _("灰色の", "L.Dark");
58         case TERM_L_WHITE: return _("明るい青灰色の", "L.Slate");
59         case TERM_VIOLET:  return _("紫の", "Violet");
60         case TERM_YELLOW:  return _("黄色の", "Yellow");
61         case TERM_L_RED:   return _("明るい赤の", "L.Red");
62         case TERM_L_GREEN: return _("明るい緑の", "L.Green");
63         case TERM_L_BLUE:  return _("明るい青の", "L.Blue");
64         case TERM_L_UMBER: return _("明るい琥珀色の", "L.Umber");
65         }
66
67         return _("変な色の", "Icky");
68 }
69
70
71
72 /*
73  * A tval grouper
74  */
75 typedef struct
76 {
77         OBJECT_TYPE_VALUE tval;
78         concptr name;
79 } grouper;
80
81
82
83 /*
84  * Item Spoilers by: benh@phial.com (Ben Harrison)
85  */
86
87
88  /*
89   * The basic items categorized by type
90   */
91 static grouper group_item[] =
92 {
93         { TV_SHOT,          _("射撃物", "Ammo") },
94         { TV_ARROW,         NULL },
95         { TV_BOLT,          NULL },
96         { TV_BOW,           _("弓", "Bows") },
97         { TV_DIGGING,       _("武器", "Weapons") },
98         { TV_POLEARM,       NULL },
99         { TV_HAFTED,        NULL },
100         { TV_SWORD,         NULL },
101         { TV_SOFT_ARMOR,    _("防具 (体)", "Armour (Body)") },
102         { TV_HARD_ARMOR,    NULL },
103         { TV_DRAG_ARMOR,    NULL },
104         { TV_BOOTS,         _("防具 (その他)", "Armour (Misc)") },
105         { TV_GLOVES,        NULL },
106         { TV_HELM,          NULL },
107         { TV_CROWN,         NULL },
108         { TV_SHIELD,        NULL },
109         { TV_CLOAK,         NULL },
110
111         { TV_LITE,          _("光源", "Light Sources") },
112         { TV_AMULET,        _("アミュレット", "Amulets")},
113         { TV_RING,          _("指輪", "Rings") },
114         { TV_STAFF,         _("杖", "Staffs") },
115         { TV_WAND,          _("魔法棒", "Wands") },
116         { TV_ROD,           _("ロッド", "Rods") },
117         { TV_SCROLL,        _("巻物", "Scrolls") },
118         { TV_POTION,        _("薬", "Potions") },
119         { TV_FOOD,          _("食料", "Food") },
120
121         { TV_LIFE_BOOK,     _("魔法書 (生命)", "Books (Life)") },
122         { TV_SORCERY_BOOK,  _("魔法書 (仙術)", "Books (Sorcery)") },
123         { TV_NATURE_BOOK,   _("魔法書 (自然)", "Books (Nature)") },
124         { TV_CHAOS_BOOK,    _("魔法書 (カオス)", "Books (Chaos)") },
125         { TV_DEATH_BOOK,    _("魔法書 (暗黒)", "Books (Death)") },
126         { TV_TRUMP_BOOK,    _("魔法書 (トランプ)", "Books (Trump)") },
127         { TV_ARCANE_BOOK,   _("魔法書 (秘術)", "Books (Arcane)") },
128         { TV_CRAFT_BOOK,    _("魔法書 (匠)", "Books (Craft)") },
129         { TV_DAEMON_BOOK,   _("魔法書 (悪魔)", "Books (Daemon)") },
130         { TV_CRUSADE_BOOK,  _("魔法書 (破邪)", "Books (Crusade)") },
131         { TV_MUSIC_BOOK,    _("歌集", "Song Books") },
132         { TV_HISSATSU_BOOK, _("武芸の書", "Books (Kendo)") },
133         { TV_HEX_BOOK,      _("魔法書 (呪術)", "Books (Hex)") },
134
135         { TV_WHISTLE,       _("笛", "Whistle") },
136         { TV_CAPTURE,       _("キャプチャー・ボール", "Capture Ball") },
137         { TV_CARD,          _("エクスプレスカード", "Express Card") },
138
139         { TV_CHEST,         _("箱", "Chests") },
140
141         { TV_FIGURINE,      _("人形", "Magical Figurines") },
142         { TV_STATUE,        _("像", "Statues") },
143         { TV_CORPSE,        _("死体", "Corpses") },
144
145         { TV_SKELETON,      _("その他", "Misc") },
146         { TV_BOTTLE,        NULL },
147         { TV_JUNK,          NULL },
148         { TV_SPIKE,         NULL },
149         { TV_FLASK,         NULL },
150         { TV_PARCHMENT,     NULL },
151
152         { 0, "" }
153 };
154
155
156 /*!
157  * @brief ベースアイテムの各情報を文字列化する /
158  * Describe the kind
159  * @param player_ptr プレーヤーへの参照ポインタ
160  * @param buf 名称を返すバッファ参照ポインタ
161  * @param dam ダメージダイス記述を返すバッファ参照ポインタ
162  * @param wgt 重量記述を返すバッファ参照ポインタ
163  * @param lev 生成階記述を返すバッファ参照ポインタ
164  * @param chance 生成機会を返すバッファ参照ポインタ
165  * @param val 価値を返すバッファ参照ポインタ
166  * @param k ベースアイテムID
167  * @return なし
168  */
169 static void kind_info(player_type *player_ptr, char *buf, char *dam, char *wgt, char *chance, DEPTH *lev, PRICE *val, OBJECT_IDX k)
170 {
171         object_type forge;
172         object_type *q_ptr;
173         int i;
174         q_ptr = &forge;
175
176         /* Prepare a fake item */
177         object_prep(q_ptr, k);
178
179         /* It is known */
180         q_ptr->ident |= (IDENT_KNOWN);
181
182         /* Cancel bonuses */
183         q_ptr->pval = 0;
184         q_ptr->to_a = 0;
185         q_ptr->to_h = 0;
186         q_ptr->to_d = 0;
187
188         (*lev) = k_info[q_ptr->k_idx].level;
189         (*val) = object_value(q_ptr);
190
191         if (!buf || !dam || !chance || !wgt) return;
192
193         /* Description (too brief) */
194         object_desc(player_ptr, buf, q_ptr, (OD_NAME_ONLY | OD_STORE));
195
196         /* Misc info */
197         strcpy(dam, "");
198
199         /* Damage */
200         switch (q_ptr->tval)
201         {
202                 /* Bows */
203         case TV_BOW:
204         {
205                 break;
206         }
207
208         /* Ammo */
209         case TV_SHOT:
210         case TV_BOLT:
211         case TV_ARROW:
212         {
213                 sprintf(dam, "%dd%d", q_ptr->dd, q_ptr->ds);
214                 break;
215         }
216
217         /* Weapons */
218         case TV_HAFTED:
219         case TV_POLEARM:
220         case TV_SWORD:
221         case TV_DIGGING:
222         {
223                 sprintf(dam, "%dd%d", q_ptr->dd, q_ptr->ds);
224                 break;
225         }
226
227         /* Armour */
228         case TV_BOOTS:
229         case TV_GLOVES:
230         case TV_CLOAK:
231         case TV_CROWN:
232         case TV_HELM:
233         case TV_SHIELD:
234         case TV_SOFT_ARMOR:
235         case TV_HARD_ARMOR:
236         case TV_DRAG_ARMOR:
237         {
238                 sprintf(dam, "%d", q_ptr->ac);
239                 break;
240         }
241         }
242
243         /* Chance */
244         strcpy(chance, "");
245         for (i = 0; i < 4; i++)
246         {
247                 char chance_aux[20] = "";
248                 if (k_info[q_ptr->k_idx].chance[i] > 0)
249                 {
250                         sprintf(chance_aux, "%s%3dF:%+4d", (i != 0 ? "/" : ""),
251                                 (int)k_info[q_ptr->k_idx].locale[i], 100 / k_info[q_ptr->k_idx].chance[i]);
252                         strcat(chance, chance_aux);
253                 }
254         }
255
256
257         /* Weight */
258         sprintf(wgt, "%3d.%d", (int)(q_ptr->weight / 10), (int)(q_ptr->weight % 10));
259 }
260
261
262 /*!
263  * @brief 各ベースアイテムの情報を一行毎に記述する /
264  * @param player_ptr プレーヤーへの参照ポインタ
265  * Create a spoiler file for items
266  * @param fname ファイル名
267  * @return なし
268  */
269 static void spoil_obj_desc(player_type *player_ptr, concptr fname)
270 {
271         int i, k, s, t, n = 0, group_start = 0;
272
273         OBJECT_IDX who[200];
274
275         char buf[1024];
276
277         char wgt[80];
278         char chance[80];
279         char dam[80];
280
281         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
282
283         /* File type is "TEXT" */
284         FILE_TYPE(FILE_TYPE_TEXT);
285         fff = my_fopen(buf, "w");
286
287         if (!fff)
288         {
289                 msg_print("Cannot create spoiler file.");
290                 return;
291         }
292
293
294         /* Header */
295         fprintf(fff, "Spoiler File -- Basic Items (Hengband %d.%d.%d.%d)\n\n\n",
296                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH, FAKE_VER_EXTRA);
297
298         /* More Header */
299         fprintf(fff, "%-37s%8s%7s%5s %40s%9s\n",
300                 "Description", "Dam/AC", "Wgt", "Lev", "Chance", "Cost");
301         fprintf(fff, "%-37s%8s%7s%5s %40s%9s\n",
302                 "-------------------------------------", "------", "---", "---", "----------------", "----");
303
304         /* List the groups */
305         for (i = 0; TRUE; i++)
306         {
307                 /* Write out the group title */
308                 if (group_item[i].name)
309                 {
310                         if (n)
311                         {
312                                 /* Hack -- bubble-sort by cost and then level */
313                                 for (s = 0; s < n - 1; s++)
314                                 {
315                                         for (t = 0; t < n - 1; t++)
316                                         {
317                                                 int i1 = t;
318                                                 int i2 = t + 1;
319
320                                                 DEPTH e1;
321                                                 DEPTH e2;
322
323                                                 PRICE t1;
324                                                 PRICE t2;
325
326                                                 kind_info(player_ptr, NULL, NULL, NULL, NULL, &e1, &t1, who[i1]);
327                                                 kind_info(player_ptr, NULL, NULL, NULL, NULL, &e2, &t2, who[i2]);
328
329                                                 if ((t1 > t2) || ((t1 == t2) && (e1 > e2)))
330                                                 {
331                                                         u16b tmp = who[i1];
332                                                         who[i1] = who[i2];
333                                                         who[i2] = tmp;
334                                                 }
335                                         }
336                                 }
337
338                                 fprintf(fff, "\n\n%s\n\n", group_item[group_start].name);
339
340                                 /* Spoil each item */
341                                 for (s = 0; s < n; s++)
342                                 {
343                                         DEPTH e;
344                                         PRICE v;
345
346                                         /* Describe the kind */
347                                         kind_info(player_ptr, buf, dam, wgt, chance, &e, &v, who[s]);
348
349                                         /* Dump it */
350                                         fprintf(fff, "  %-35s%8s%7s%5d %-40s%9ld\n",
351                                                 buf, dam, wgt, (int)e, chance, (long)(v));
352                                 }
353
354                                 /* Start a new set */
355                                 n = 0;
356                         }
357
358                         /* Notice the end */
359                         if (!group_item[i].tval) break;
360
361                         /* Start a new set */
362                         group_start = i;
363                 }
364
365                 /* Acquire legal item types */
366                 for (k = 1; k < max_k_idx; k++)
367                 {
368                         object_kind *k_ptr = &k_info[k];
369
370                         /* Skip wrong tval's */
371                         if (k_ptr->tval != group_item[i].tval) continue;
372
373                         /* Hack -- Skip instant-artifacts */
374                         if (k_ptr->gen_flags & (TRG_INSTA_ART)) continue;
375
376                         /* Save the index */
377                         who[n++] = (u16b)k;
378                 }
379         }
380
381
382         /* Check for errors */
383         if (ferror(fff) || my_fclose(fff))
384         {
385                 msg_print("Cannot close spoiler file.");
386                 return;
387         }
388
389         msg_print("Successfully created a spoiler file.");
390 }
391
392
393 /*
394  * Artifact Spoilers by: randy@PICARD.tamu.edu (Randy Hutson)
395  */
396
397
398  /*
399   * Returns a "+" string if a number is non-negative and an empty
400   * string if negative
401   */
402 #define POSITIZE(v) (((v) >= 0) ? "+" : "")
403
404   /*
405    * These are used to format the artifact spoiler file. INDENT1 is used
406    * to indent all but the first line of an artifact spoiler. INDENT2 is
407    * used when a line "wraps". (Bladeturner's resistances cause this.)
408    */
409 #define INDENT1 "    "
410 #define INDENT2 "      "
411
412    /*
413         * MAX_LINE_LEN specifies when a line should wrap.
414         */
415 #define MAX_LINE_LEN 75
416
417         /*
418          * Given an array, determine how many elements are in the array
419          */
420 #define N_ELEMENTS(a) (sizeof (a) / sizeof ((a)[0]))
421
422          /*
423           * The artifacts categorized by type
424           */
425 static grouper group_artifact[] =
426 {
427 #ifdef JP
428         { TV_SWORD,             "刀剣" },
429         { TV_POLEARM,           "槍/斧" },
430         { TV_HAFTED,            "鈍器" },
431         { TV_DIGGING,           "シャベル/つるはし" },
432         { TV_BOW,               "飛び道具" },
433         { TV_ARROW,             "矢" },
434         { TV_BOLT,              NULL },
435
436         { TV_SOFT_ARMOR,        "鎧" },
437         { TV_HARD_ARMOR,        NULL },
438         { TV_DRAG_ARMOR,        NULL },
439
440         { TV_CLOAK,             "クローク" },
441         { TV_SHIELD,            "盾" },
442         { TV_CARD,              NULL },
443         { TV_HELM,              "兜/冠" },
444         { TV_CROWN,             NULL },
445         { TV_GLOVES,            "籠手" },
446         { TV_BOOTS,             "靴" },
447
448         { TV_LITE,              "光源" },
449         { TV_AMULET,            "アミュレット" },
450         { TV_RING,              "指輪" },
451 #else
452         { TV_SWORD,             "Edged Weapons" },
453         { TV_POLEARM,           "Polearms" },
454         { TV_HAFTED,            "Hafted Weapons" },
455         { TV_DIGGING,           "Shovels/Picks" },
456         { TV_BOW,               "Bows" },
457         { TV_ARROW,             "Ammo" },
458         { TV_BOLT,              NULL },
459
460         { TV_SOFT_ARMOR,        "Body Armor" },
461         { TV_HARD_ARMOR,        NULL },
462         { TV_DRAG_ARMOR,        NULL },
463
464         { TV_CLOAK,             "Cloaks" },
465         { TV_SHIELD,            "Shields" },
466         { TV_CARD,              NULL },
467         { TV_HELM,              "Helms/Crowns" },
468         { TV_CROWN,             NULL },
469         { TV_GLOVES,            "Gloves" },
470         { TV_BOOTS,             "Boots" },
471
472         { TV_LITE,              "Light Sources" },
473         { TV_AMULET,            "Amulets" },
474         { TV_RING,              "Rings" },
475 #endif
476
477         { 0, NULL }
478 };
479
480
481
482 /*
483  * Pair together a constant flag with a textual description.
484  *
485  * Used by both "init.c" and "wiz-spo.c".
486  *
487  * Note that it sometimes more efficient to actually make an array
488  * of textual names, where entry 'N' is assumed to be paired with
489  * the flag whose value is "1L << N", but that requires hard-coding.
490  */
491 typedef struct flag_desc
492 {
493         const int flag;
494         concptr const desc;
495 } flag_desc;
496
497
498
499 /*
500  * These are used for "+3 to STR, DEX", etc. These are separate from
501  * the other pval affected traits to simplify the case where an object
502  * affects all stats.  In this case, "All stats" is used instead of
503  * listing each stat individually.
504  */
505
506 static flag_desc stat_flags_desc[] =
507 {
508 #ifdef JP
509         { TR_STR,        "腕力" },
510         { TR_INT,        "知能" },
511         { TR_WIS,        "賢さ" },
512         { TR_DEX,        "器用さ" },
513         { TR_CON,        "耐久力" },
514         { TR_CHR,        "魅力" }
515 #else
516         { TR_STR,        "STR" },
517         { TR_INT,        "INT" },
518         { TR_WIS,        "WIS" },
519         { TR_DEX,        "DEX" },
520         { TR_CON,        "CON" },
521         { TR_CHR,        "CHR" }
522 #endif
523 };
524
525 /*
526  * Besides stats, these are the other player traits
527  * which may be affected by an object's pval
528  */
529
530 static flag_desc pval_flags1_desc[] =
531 {
532 #ifdef JP
533         { TR_MAGIC_MASTERY,    "魔法道具使用能力" },
534         { TR_STEALTH,    "隠密" },
535         { TR_SEARCH,     "探索" },
536         { TR_INFRA,      "赤外線視力" },
537         { TR_TUNNEL,     "採掘" },
538         { TR_BLOWS,      "攻撃回数" },
539         { TR_SPEED,      "スピード" }
540 #else
541         { TR_STEALTH,    "Stealth" },
542         { TR_SEARCH,     "Searching" },
543         { TR_INFRA,      "Infravision" },
544         { TR_TUNNEL,     "Tunneling" },
545         { TR_BLOWS,      "Attacks" },
546         { TR_SPEED,      "Speed" }
547 #endif
548 };
549
550 /*
551  * Slaying preferences for weapons
552  */
553
554 static flag_desc slay_flags_desc[] =
555 {
556 #ifdef JP
557         { TR_SLAY_ANIMAL,        "動物" },
558         { TR_KILL_ANIMAL,        "*動物*" },
559         { TR_SLAY_EVIL,          "邪悪" },
560         { TR_KILL_EVIL,          "*邪悪*" },
561         { TR_SLAY_HUMAN,         "人間" },
562         { TR_KILL_HUMAN,         "*人間*" },
563         { TR_SLAY_UNDEAD,        "アンデッド" },
564         { TR_KILL_UNDEAD,        "*アンデッド*" },
565         { TR_SLAY_DEMON,         "悪魔" },
566         { TR_KILL_DEMON,         "*悪魔*" },
567         { TR_SLAY_ORC,           "オーク" },
568         { TR_KILL_ORC,           "*オーク*" },
569         { TR_SLAY_TROLL,         "トロル" },
570         { TR_KILL_TROLL,         "*トロル*" },
571         { TR_SLAY_GIANT,         "巨人" },
572         { TR_KILL_GIANT,         "*巨人*" },
573         { TR_SLAY_DRAGON,        "ドラゴン" },
574         { TR_KILL_DRAGON,        "*ドラゴン*" },
575 #else
576         { TR_SLAY_ANIMAL,        "Animal" },
577         { TR_KILL_ANIMAL,        "XAnimal" },
578         { TR_SLAY_EVIL,          "Evil" },
579         { TR_KILL_EVIL,          "XEvil" },
580         { TR_SLAY_HUMAN,         "Human" },
581         { TR_KILL_HUMAN,         "XHuman" },
582         { TR_SLAY_UNDEAD,        "Undead" },
583         { TR_KILL_UNDEAD,        "XUndead" },
584         { TR_SLAY_DEMON,         "Demon" },
585         { TR_KILL_DEMON,         "XDemon" },
586         { TR_SLAY_ORC,           "Orc" },
587         { TR_KILL_ORC,           "XOrc" },
588         { TR_SLAY_TROLL,         "Troll" },
589         { TR_KILL_TROLL,         "XTroll" },
590         { TR_SLAY_GIANT,         "Giant" },
591         { TR_KILL_GIANT,         "Xgiant" },
592         { TR_SLAY_DRAGON,        "Dragon" },
593         { TR_KILL_DRAGON,        "Xdragon" }
594 #endif
595 };
596
597 /*
598  * Elemental brands for weapons
599  *
600  * Clearly, TR1_IMPACT is a bit out of place here. To simplify
601  * coding, it has been included here along with the elemental
602  * brands. It does seem to fit in with the brands and slaying
603  * more than the miscellaneous section.
604  */
605 static flag_desc brand_flags_desc[] =
606 {
607 #ifdef JP
608         { TR_BRAND_ACID,         "溶解" },
609         { TR_BRAND_ELEC,         "電撃" },
610         { TR_BRAND_FIRE,         "焼棄" },
611         { TR_BRAND_COLD,         "凍結" },
612         { TR_BRAND_POIS,         "毒殺" },
613
614         { TR_FORCE_WEAPON,       "理力" },
615         { TR_CHAOTIC,            "混沌" },
616         { TR_VAMPIRIC,           "吸血" },
617         { TR_IMPACT,             "地震" },
618         { TR_VORPAL,             "切れ味" },
619 #else
620         { TR_BRAND_ACID,         "Acid Brand" },
621         { TR_BRAND_ELEC,         "Lightning Brand" },
622         { TR_BRAND_FIRE,         "Flame Tongue" },
623         { TR_BRAND_COLD,         "Frost Brand" },
624         { TR_BRAND_POIS,         "Poisoned" },
625
626         { TR_FORCE_WEAPON,       "Force" },
627         { TR_CHAOTIC,            "Mark of Chaos" },
628         { TR_VAMPIRIC,           "Vampiric" },
629         { TR_IMPACT,             "Earthquake impact on hit" },
630         { TR_VORPAL,             "Very sharp" },
631 #endif
632 };
633
634
635 /*
636  * The 15 resistables
637  */
638 static const flag_desc resist_flags_desc[] =
639 {
640 #ifdef JP
641         { TR_RES_ACID,   "酸" },
642         { TR_RES_ELEC,   "電撃" },
643         { TR_RES_FIRE,   "火炎" },
644         { TR_RES_COLD,   "冷気" },
645         { TR_RES_POIS,   "毒" },
646         { TR_RES_FEAR,   "恐怖"},
647         { TR_RES_LITE,   "閃光" },
648         { TR_RES_DARK,   "暗黒" },
649         { TR_RES_BLIND,  "盲目" },
650         { TR_RES_CONF,   "混乱" },
651         { TR_RES_SOUND,  "轟音" },
652         { TR_RES_SHARDS, "破片" },
653         { TR_RES_NETHER, "地獄" },
654         { TR_RES_NEXUS,  "因果混乱" },
655         { TR_RES_CHAOS,  "カオス" },
656         { TR_RES_DISEN,  "劣化" },
657 #else
658         { TR_RES_ACID,   "Acid" },
659         { TR_RES_ELEC,   "Lightning" },
660         { TR_RES_FIRE,   "Fire" },
661         { TR_RES_COLD,   "Cold" },
662         { TR_RES_POIS,   "Poison" },
663         { TR_RES_FEAR,   "Fear"},
664         { TR_RES_LITE,   "Light" },
665         { TR_RES_DARK,   "Dark" },
666         { TR_RES_BLIND,  "Blindness" },
667         { TR_RES_CONF,   "Confusion" },
668         { TR_RES_SOUND,  "Sound" },
669         { TR_RES_SHARDS, "Shards" },
670         { TR_RES_NETHER, "Nether" },
671         { TR_RES_NEXUS,  "Nexus" },
672         { TR_RES_CHAOS,  "Chaos" },
673         { TR_RES_DISEN,  "Disenchantment" },
674 #endif
675 };
676
677 /*
678  * Elemental immunities (along with poison)
679  */
680
681 static const flag_desc immune_flags_desc[] =
682 {
683 #ifdef JP
684         { TR_IM_ACID,    "酸" },
685         { TR_IM_ELEC,    "電撃" },
686         { TR_IM_FIRE,    "火炎" },
687         { TR_IM_COLD,    "冷気" },
688 #else
689         { TR_IM_ACID,    "Acid" },
690         { TR_IM_ELEC,    "Lightning" },
691         { TR_IM_FIRE,    "Fire" },
692         { TR_IM_COLD,    "Cold" },
693 #endif
694 };
695
696 /*
697  * Sustain stats -  these are given their "own" line in the
698  * spoiler file, mainly for simplicity
699  */
700 static const flag_desc sustain_flags_desc[] =
701 {
702 #ifdef JP
703         { TR_SUST_STR,   "腕力" },
704         { TR_SUST_INT,   "知能" },
705         { TR_SUST_WIS,   "賢さ" },
706         { TR_SUST_DEX,   "器用さ" },
707         { TR_SUST_CON,   "耐久力" },
708         { TR_SUST_CHR,   "魅力" },
709 #else
710         { TR_SUST_STR,   "STR" },
711         { TR_SUST_INT,   "INT" },
712         { TR_SUST_WIS,   "WIS" },
713         { TR_SUST_DEX,   "DEX" },
714         { TR_SUST_CON,   "CON" },
715         { TR_SUST_CHR,   "CHR" },
716 #endif
717 };
718
719 /*
720  * Miscellaneous magic given by an object's "flags2" field
721  */
722
723 static const flag_desc misc_flags2_desc[] =
724 {
725 #ifdef JP
726         { TR_THROW,      "投擲" },
727         { TR_REFLECT,    "反射" },
728         { TR_FREE_ACT,   "麻痺知らず" },
729         { TR_HOLD_EXP,   "経験値維持" },
730 #else
731         { TR_THROW,      "Throwing" },
732         { TR_REFLECT,    "Reflection" },
733         { TR_FREE_ACT,   "Free Action" },
734         { TR_HOLD_EXP,   "Hold Experience" },
735 #endif
736 };
737
738 /*
739  * Miscellaneous magic given by an object's "flags3" field
740  *
741  * Note that cursed artifacts and objects with permanent light
742  * are handled "directly" -- see analyze_misc_magic()
743  */
744
745 static const flag_desc misc_flags3_desc[] =
746 {
747 #ifdef JP
748         { TR_SH_FIRE,            "火炎オーラ" },
749         { TR_SH_ELEC,            "電撃オーラ" },
750         { TR_SH_COLD,            "冷気オーラ" },
751         { TR_NO_TELE,            "反テレポート" },
752         { TR_NO_MAGIC,           "反魔法" },
753         { TR_LEVITATION,         "浮遊" },
754         { TR_SEE_INVIS,          "可視透明" },
755         { TR_TELEPATHY,          "テレパシー" },
756         { TR_ESP_ANIMAL,         "動物感知" },
757         { TR_ESP_UNDEAD,         "不死感知" },
758         { TR_ESP_DEMON,          "悪魔感知" },
759         { TR_ESP_ORC,            "オーク感知" },
760         { TR_ESP_TROLL,          "トロル感知" },
761         { TR_ESP_GIANT,          "巨人感知" },
762         { TR_ESP_DRAGON,         "ドラゴン感知" },
763         { TR_ESP_HUMAN,          "人間感知" },
764         { TR_ESP_EVIL,           "邪悪感知" },
765         { TR_ESP_GOOD,           "善良感知" },
766         { TR_ESP_NONLIVING,      "無生物感知" },
767         { TR_ESP_UNIQUE,         "ユニーク感知" },
768         { TR_SLOW_DIGEST,        "遅消化" },
769         { TR_REGEN,              "急速回復" },
770         { TR_WARNING,            "警告" },
771         /*      { TR_XTRA_MIGHT,         "強力射撃" }, */
772                 { TR_XTRA_SHOTS,         "追加射撃" },        /* always +1? */
773                 { TR_DRAIN_EXP,          "経験値吸収" },
774                 { TR_AGGRAVATE,          "反感" },
775                 { TR_BLESSED,            "祝福" },
776                 { TR_DEC_MANA,           "消費魔力減少" },
777         #else
778                 { TR_SH_FIRE,            "Fiery Aura" },
779                 { TR_SH_ELEC,            "Electric Aura" },
780                 { TR_SH_COLD,            "Coldly Aura" },
781                 { TR_NO_TELE,            "Prevent Teleportation" },
782                 { TR_NO_MAGIC,           "Anti-Magic" },
783                 { TR_LEVITATION,            "Levitation" },
784                 { TR_SEE_INVIS,          "See Invisible" },
785                 { TR_TELEPATHY,          "ESP" },
786                 { TR_ESP_ANIMAL,         "Sense Animal" },
787                 { TR_ESP_UNDEAD,         "Sense Undead" },
788                 { TR_ESP_DEMON,          "Sense Demon" },
789                 { TR_ESP_ORC,            "Sense Orc" },
790                 { TR_ESP_TROLL,          "Sense Troll" },
791                 { TR_ESP_GIANT,          "Sense Giant" },
792                 { TR_ESP_DRAGON,         "Sense Dragon" },
793                 { TR_ESP_HUMAN,          "Sense Human" },
794                 { TR_ESP_EVIL,           "Sense Evil" },
795                 { TR_ESP_GOOD,           "Sense Good" },
796                 { TR_ESP_NONLIVING,      "Sense Nonliving" },
797                 { TR_ESP_UNIQUE,         "Sense Unique" },
798                 { TR_SLOW_DIGEST,        "Slow Digestion" },
799                 { TR_REGEN,              "Regeneration" },
800                 { TR_WARNING,            "Warning" },
801                 /*      { TR_XTRA_MIGHT,         "Extra Might" }, */
802                         { TR_XTRA_SHOTS,         "+1 Extra Shot" },        /* always +1? */
803                         { TR_DRAIN_EXP,          "Drains Experience" },
804                         { TR_AGGRAVATE,          "Aggravates" },
805                         { TR_BLESSED,            "Blessed Blade" },
806                         { TR_DEC_MANA,           "Decrease Mana Consumption Rate" },
807                 #endif
808 };
809
810
811 /*
812  * A special type used just for deailing with pvals
813  */
814 typedef struct
815 {
816         /*
817          * This will contain a string such as "+2", "-10", etc.
818          */
819         char pval_desc[12];
820
821         /*
822          * A list of various player traits affected by an object's pval such
823          * as stats, speed, stealth, etc.  "Extra attacks" is NOT included in
824          * this list since it will probably be desirable to format its
825          * description differently.
826          *
827          * Note that room need only be reserved for the number of stats - 1
828          * since the description "All stats" is used if an object affects all
829          * all stats. Also, room must be reserved for a sentinel NULL pointer.
830          *
831          * This will be a list such as ["STR", "DEX", "Stealth", NULL] etc.
832          *
833          * This list includes extra attacks, for simplicity.
834          */
835         concptr pval_affects[N_ELEMENTS(stat_flags_desc) - 1 +
836                 N_ELEMENTS(pval_flags1_desc) + 1];
837
838 } pval_info_type;
839
840
841 /*
842  * An "object analysis structure"
843  *
844  * It will be filled with descriptive strings detailing an object's
845  * various magical powers. The "ignore X" traits are not noted since
846  * all artifacts ignore "normal" destruction.
847  */
848
849 typedef struct
850 {
851         /* "The Longsword Dragonsmiter (6d4) (+20, +25)" */
852         char description[MAX_NLEN];
853
854         /* Description of what is affected by an object's pval */
855         pval_info_type pval_info;
856
857         /* A list of an object's slaying preferences */
858         concptr slays[N_ELEMENTS(slay_flags_desc) + 1];
859
860         /* A list if an object's elemental brands */
861         concptr brands[N_ELEMENTS(brand_flags_desc) + 1];
862
863         /* A list of immunities granted by an object */
864         concptr immunities[N_ELEMENTS(immune_flags_desc) + 1];
865
866         /* A list of resistances granted by an object */
867         concptr resistances[N_ELEMENTS(resist_flags_desc) + 1];
868
869         /* A list of stats sustained by an object */
870         concptr sustains[N_ELEMENTS(sustain_flags_desc) - 1 + 1];
871
872         /* A list of various magical qualities an object may have */
873         concptr misc_magic[N_ELEMENTS(misc_flags2_desc) + N_ELEMENTS(misc_flags3_desc)
874                 + 1       /* Permanent Light */
875                 + 1       /* TY curse */
876                 + 1       /* type of curse */
877                 + 1];     /* sentinel NULL */
878
879 /* Additional ability or resistance */
880         char addition[80];
881
882         /* A string describing an artifact's activation */
883         concptr activation;
884
885         /* "Level 20, Rarity 30, 3.0 lbs, 20000 Gold" */
886         char misc_desc[80];
887 } obj_desc_list;
888
889
890 /*!
891  * @brief ファイルポインタ先に同じ文字を複数出力する /
892  * Write out `n' of the character `c' to the spoiler file
893  * @param n 出力する数
894  * @param c 出力するキャラクタ
895  * @return なし
896  */
897 static void spoiler_out_n_chars(int n, char c)
898 {
899         while (--n >= 0) fputc(c, fff);
900 }
901
902
903 /*!
904  * @brief ファイルポインタ先に改行を複数出力する /
905  * Write out `n' blank lines to the spoiler file
906  * @param n 改行を出力する数
907  * @return なし
908  */
909 static void spoiler_blanklines(int n)
910 {
911         spoiler_out_n_chars(n, '\n');
912 }
913
914
915 /*!
916  * @brief ファイルポインタ先に複数のハイフンで装飾した文字列を出力する /
917  * Write a line to the spoiler file and then "underline" it with hypens
918  * @param str 出力したい文字列
919  * @return なし
920  */
921 static void spoiler_underline(concptr str)
922 {
923         fprintf(fff, "%s\n", str);
924         spoiler_out_n_chars(strlen(str), '-');
925         fprintf(fff, "\n");
926 }
927
928
929
930 /*!
931  * @brief アーティファクトの特性一覧を出力する /
932  * Write a line to the spoiler file and then "underline" it with hypens
933  * @param art_flags アーティファクトのフラグ群
934  * @param flag_ptr フラグ記述情報の参照ポインタ
935  * @param desc_ptr 記述内容を返すための文字列参照ポインタ
936  * @param n_elmnts フラグの要素数
937  * @return desc_ptrと同じアドレス
938  * @details
939  * <pre>
940  * This function does most of the actual "analysis". Given a set of bit flags
941  * (which will be from one of the flags fields from the object in question),
942  * a "flag description structure", a "description list", and the number of
943  * elements in the "flag description structure", this function sets the
944  * "description list" members to the appropriate descriptions contained in
945  * the "flag description structure".
946  * The possibly updated description pointer is returned.
947  * </pre>
948  */
949 static concptr *spoiler_flag_aux(const BIT_FLAGS art_flags[TR_FLAG_SIZE],
950         const flag_desc *flag_ptr,
951         concptr *desc_ptr, const int n_elmnts)
952 {
953         int i;
954
955         for (i = 0; i < n_elmnts; ++i)
956         {
957                 if (have_flag(art_flags, flag_ptr[i].flag))
958                 {
959                         *desc_ptr++ = flag_ptr[i].desc;
960                 }
961         }
962
963         return desc_ptr;
964 }
965
966
967 /*!
968  * @brief アイテムの特定記述内容を返す /
969  * Acquire a "basic" description "The Cloak of Death [1,+10]"
970  * @param o_ptr 記述を得たいオブジェクトの参照ポインタ
971  * @param desc_ptr 記述内容を返すための文字列参照ポインタ
972  * @return なし
973  */
974 static void analyze_general(player_type *player_ptr, object_type *o_ptr, char *desc_ptr)
975 {
976         /* Get a "useful" description of the object */
977         object_desc(player_ptr, desc_ptr, o_ptr, (OD_NAME_AND_ENCHANT | OD_STORE));
978 }
979
980
981 /*!
982  * @brief アーティファクトがプレイヤーに与えるpval修正を構造体に収める /
983  * List "player traits" altered by an artifact's pval. These include stats,
984  * speed, infravision, tunneling, stealth, searching, and extra attacks.
985  * @param o_ptr オブジェクト構造体の参照ポインタ
986  * @param pi_ptr pval修正構造体の参照ポインタ
987  * @return なし
988  */
989 static void analyze_pval(object_type *o_ptr, pval_info_type *pi_ptr)
990 {
991         BIT_FLAGS flgs[TR_FLAG_SIZE];
992
993         concptr *affects_list;
994
995         /* If pval == 0, there is nothing to do. */
996         if (!o_ptr->pval)
997         {
998                 /* An "empty" pval description indicates that pval == 0 */
999                 pi_ptr->pval_desc[0] = '\0';
1000                 return;
1001         }
1002         object_flags(o_ptr, flgs);
1003
1004         affects_list = pi_ptr->pval_affects;
1005
1006         /* Create the "+N" string */
1007         sprintf(pi_ptr->pval_desc, "%s%d", POSITIZE(o_ptr->pval), o_ptr->pval);
1008
1009         /* First, check to see if the pval affects all stats */
1010         if (have_flag(flgs, TR_STR) && have_flag(flgs, TR_INT) &&
1011                 have_flag(flgs, TR_WIS) && have_flag(flgs, TR_DEX) &&
1012                 have_flag(flgs, TR_CON) && have_flag(flgs, TR_CHR))
1013         {
1014                 *affects_list++ = _("全能力", "All stats");
1015         }
1016
1017         /* Are any stats affected? */
1018         else if (have_flag(flgs, TR_STR) || have_flag(flgs, TR_INT) ||
1019                 have_flag(flgs, TR_WIS) || have_flag(flgs, TR_DEX) ||
1020                 have_flag(flgs, TR_CON) || have_flag(flgs, TR_CHR))
1021         {
1022                 affects_list = spoiler_flag_aux(flgs, stat_flags_desc,
1023                         affects_list,
1024                         N_ELEMENTS(stat_flags_desc));
1025         }
1026
1027         /* And now the "rest" */
1028         affects_list = spoiler_flag_aux(flgs, pval_flags1_desc,
1029                 affects_list,
1030                 N_ELEMENTS(pval_flags1_desc));
1031
1032         /* Terminate the description list */
1033         *affects_list = NULL;
1034 }
1035
1036 /*!
1037  * @brief アーティファクトの種族スレイ特性を構造体に収める /
1038  * Note the slaying specialties of a weapon
1039  * @param o_ptr オブジェクト構造体の参照ポインタ
1040  * @param slay_list 種族スレイ構造体の参照ポインタ
1041  * @return なし
1042  */
1043 static void analyze_slay(object_type *o_ptr, concptr *slay_list)
1044 {
1045         BIT_FLAGS flgs[TR_FLAG_SIZE];
1046
1047         object_flags(o_ptr, flgs);
1048
1049         slay_list = spoiler_flag_aux(flgs, slay_flags_desc, slay_list,
1050                 N_ELEMENTS(slay_flags_desc));
1051
1052         /* Terminate the description list */
1053         *slay_list = NULL;
1054 }
1055
1056
1057 /*!
1058  * @brief アーティファクトの属性ブランド特性を構造体に収める /
1059  * Note an object's elemental brands
1060  * @param o_ptr オブジェクト構造体の参照ポインタ
1061  * @param brand_list 属性ブランド構造体の参照ポインタ
1062  * @return なし
1063  */
1064 static void analyze_brand(object_type *o_ptr, concptr *brand_list)
1065 {
1066         BIT_FLAGS flgs[TR_FLAG_SIZE];
1067
1068         object_flags(o_ptr, flgs);
1069
1070         brand_list = spoiler_flag_aux(flgs, brand_flags_desc, brand_list,
1071                 N_ELEMENTS(brand_flags_desc));
1072
1073         /* Terminate the description list */
1074         *brand_list = NULL;
1075 }
1076
1077
1078 /*!
1079  * @brief アーティファクトの通常耐性を構造体に収める /
1080  * Note an object's elemental brands
1081  * @param o_ptr オブジェクト構造体の参照ポインタ
1082  * @param resist_list 通常耐性構造体の参照ポインタ
1083  * @return なし
1084  */
1085 static void analyze_resist(object_type *o_ptr, concptr *resist_list)
1086 {
1087         BIT_FLAGS flgs[TR_FLAG_SIZE];
1088
1089         object_flags(o_ptr, flgs);
1090
1091         resist_list = spoiler_flag_aux(flgs, resist_flags_desc,
1092                 resist_list, N_ELEMENTS(resist_flags_desc));
1093
1094         /* Terminate the description list */
1095         *resist_list = NULL;
1096 }
1097
1098
1099 /*!
1100  * @brief アーティファクトの免疫特性を構造体に収める /
1101  * Note the immunities granted by an object
1102  * @param o_ptr オブジェクト構造体の参照ポインタ
1103  * @param immune_list 免疫構造体の参照ポインタ
1104  * @return なし
1105  */
1106 static void analyze_immune(object_type *o_ptr, concptr *immune_list)
1107 {
1108         BIT_FLAGS flgs[TR_FLAG_SIZE];
1109
1110         object_flags(o_ptr, flgs);
1111
1112         immune_list = spoiler_flag_aux(flgs, immune_flags_desc,
1113                 immune_list, N_ELEMENTS(immune_flags_desc));
1114
1115         /* Terminate the description list */
1116         *immune_list = NULL;
1117 }
1118
1119
1120 /*!
1121  * @brief アーティファクトの維持特性を構造体に収める /
1122  * Note which stats an object sustains
1123  * @param o_ptr オブジェクト構造体の参照ポインタ
1124  * @param sustain_list 維持特性構造体の参照ポインタ
1125  * @return なし
1126  */
1127 static void analyze_sustains(object_type *o_ptr, concptr *sustain_list)
1128 {
1129         BIT_FLAGS flgs[TR_FLAG_SIZE];
1130
1131         object_flags(o_ptr, flgs);
1132
1133         /* Simplify things if an item sustains all stats */
1134         if (have_flag(flgs, TR_SUST_STR) && have_flag(flgs, TR_SUST_INT) &&
1135                 have_flag(flgs, TR_SUST_WIS) && have_flag(flgs, TR_SUST_DEX) &&
1136                 have_flag(flgs, TR_SUST_CON) && have_flag(flgs, TR_SUST_CHR))
1137         {
1138                 *sustain_list++ = _("全能力", "All stats");
1139         }
1140
1141         /* Should we bother? */
1142         else if (have_flag(flgs, TR_SUST_STR) || have_flag(flgs, TR_SUST_INT) ||
1143                 have_flag(flgs, TR_SUST_WIS) || have_flag(flgs, TR_SUST_DEX) ||
1144                 have_flag(flgs, TR_SUST_CON) || have_flag(flgs, TR_SUST_CHR))
1145         {
1146                 sustain_list = spoiler_flag_aux(flgs, sustain_flags_desc,
1147                         sustain_list,
1148                         N_ELEMENTS(sustain_flags_desc));
1149         }
1150
1151         /* Terminate the description list */
1152         *sustain_list = NULL;
1153 }
1154
1155
1156 /*!
1157  * @brief アーティファクトのその他の特性を構造体に収める /
1158  * Note miscellaneous powers bestowed by an artifact such as see invisible,
1159  * free action, permanent light, etc.
1160  * @param o_ptr オブジェクト構造体の参照ポインタ
1161  * @param misc_list その他の特性構造体の参照ポインタ
1162  * @return なし
1163  */
1164 static void analyze_misc_magic(object_type *o_ptr, concptr *misc_list)
1165 {
1166         BIT_FLAGS flgs[TR_FLAG_SIZE];
1167         POSITION rad;
1168         char desc[256];
1169
1170         object_flags(o_ptr, flgs);
1171
1172         misc_list = spoiler_flag_aux(flgs, misc_flags2_desc, misc_list,
1173                 N_ELEMENTS(misc_flags2_desc));
1174
1175         misc_list = spoiler_flag_aux(flgs, misc_flags3_desc, misc_list, N_ELEMENTS(misc_flags3_desc));
1176
1177         /*
1178          * Glowing artifacts -- small radius light.
1179         */
1180         rad = 0;
1181         if (have_flag(flgs, TR_LITE_1))  rad += 1;
1182         if (have_flag(flgs, TR_LITE_2))  rad += 2;
1183         if (have_flag(flgs, TR_LITE_3))  rad += 3;
1184         if (have_flag(flgs, TR_LITE_M1)) rad -= 1;
1185         if (have_flag(flgs, TR_LITE_M2)) rad -= 2;
1186         if (have_flag(flgs, TR_LITE_M3)) rad -= 3;
1187
1188         if (o_ptr->name2 == EGO_LITE_SHINE) rad++;
1189
1190         if (have_flag(flgs, TR_LITE_FUEL))
1191         {
1192                 if (rad > 0) sprintf(desc, _("それは燃料補給によって明かり(半径 %d)を授ける。", "It provides light (radius %d) when fueled."), (int)rad);
1193         }
1194         else
1195         {
1196                 if (rad > 0) sprintf(desc, _("永久光源(半径 %d)", "Permanent Light(radius %d)"), (int)rad);
1197                 if (rad < 0) sprintf(desc, _("永久光源(半径-%d)。", "Permanent Light(radius -%d)"), (int)-rad);
1198         }
1199
1200         if (rad != 0) *misc_list++ = quark_str(quark_add(desc));
1201
1202         /*
1203          * Handle cursed objects here to avoid redundancies such as noting
1204          * that a permanently cursed object is heavily cursed as well as
1205          * being "lightly cursed".
1206          */
1207
1208          /*     if (object_is_cursed(o_ptr)) */
1209         {
1210                 if (have_flag(flgs, TR_TY_CURSE))
1211                 {
1212                         *misc_list++ = _("太古の怨念", "Ancient Curse");
1213                 }
1214                 if (o_ptr->curse_flags & TRC_PERMA_CURSE)
1215                 {
1216                         *misc_list++ = _("永遠の呪い", "Permanently Cursed");
1217                 }
1218                 else if (o_ptr->curse_flags & TRC_HEAVY_CURSE)
1219                 {
1220                         *misc_list++ = _("強力な呪い", "Heavily Cursed");
1221                 }
1222                 /*              else */
1223                 else if (o_ptr->curse_flags & TRC_CURSED)
1224                 {
1225                         *misc_list++ = _("呪い", "Cursed");
1226                 }
1227                 if (have_flag(flgs, TR_ADD_L_CURSE))
1228                 {
1229                         *misc_list++ = _("呪いを増やす", "Cursing");
1230                 }
1231                 if (have_flag(flgs, TR_ADD_H_CURSE))
1232                 {
1233                         *misc_list++ = _("強力な呪いを増やす", "Heavily Cursing");
1234                 }
1235         }
1236
1237         /* Terminate the description list */
1238         *misc_list = NULL;
1239 }
1240
1241
1242 /*!
1243  * @brief アーティファクトの追加ランダム特性を構造体に収める /
1244  * Note additional ability and/or resistance of fixed artifacts
1245  * @param o_ptr オブジェクト構造体の参照ポインタ
1246  * @param addition 追加ランダム耐性構造体の参照ポインタ
1247  * @return なし
1248  */
1249 static void analyze_addition(object_type *o_ptr, char *addition)
1250 {
1251         artifact_type *a_ptr = &a_info[o_ptr->name1];
1252
1253         /* Init */
1254         strcpy(addition, "");
1255
1256         if ((a_ptr->gen_flags & TRG_XTRA_POWER) && (a_ptr->gen_flags & TRG_XTRA_H_RES)) strcat(addition, _("能力and耐性", "Ability and Resistance"));
1257         else if (a_ptr->gen_flags & TRG_XTRA_POWER)
1258         {
1259                 strcat(addition, _("能力", "Ability"));
1260                 if (a_ptr->gen_flags & TRG_XTRA_RES_OR_POWER) strcat(addition, _("(1/2でand耐性)", "(plus Resistance about 1/2)"));
1261         }
1262         else if (a_ptr->gen_flags & TRG_XTRA_H_RES)
1263         {
1264                 strcat(addition, _("耐性", "Resistance"));
1265                 if (a_ptr->gen_flags & TRG_XTRA_RES_OR_POWER) strcat(addition, _("(1/2でand能力)", "(plus Ability about 1/2)"));
1266         }
1267         else if (a_ptr->gen_flags & TRG_XTRA_RES_OR_POWER) strcat(addition, _("能力or耐性", "Ability or Resistance"));
1268 }
1269
1270
1271 /*!
1272  * @brief アーティファクトの基本情報を文字列に収める /
1273  * Determine the minimum depth an artifact can appear, its rarity, its weight,
1274  * and its value in gold pieces
1275  * @param o_ptr オブジェクト構造体の参照ポインタ
1276  * @param misc_desc 基本情報を収める文字列参照ポインタ
1277  * @return なし
1278  */
1279 static void analyze_misc(object_type *o_ptr, char *misc_desc)
1280 {
1281         artifact_type *a_ptr = &a_info[o_ptr->name1];
1282
1283         sprintf(misc_desc, _("レベル %d, 希少度 %u, %d.%d kg, $%ld", "Level %d, Rarity %u, %d.%d lbs, %ld Gold"), (int)a_ptr->level, a_ptr->rarity,
1284 #ifdef JP
1285                 lbtokg1(a_ptr->weight), lbtokg2(a_ptr->weight), (long int)a_ptr->cost);
1286 #else
1287                 a_ptr->weight / 10, a_ptr->weight % 10, (long int)a_ptr->cost);
1288 #endif
1289 }
1290
1291
1292 /*!
1293  * @brief アーティファクトの情報全体を構造体に収める /
1294  * Fill in an object description structure for a given object
1295  * and its value in gold pieces
1296  * @param player_ptr プレーヤーへの参照ポインタ
1297  * @param o_ptr オブジェクト構造体の参照ポインタ
1298  * @param desc_ptr 全アーティファクト情報を収める文字列参照ポインタ
1299  * @return なし
1300  */
1301 static void object_analyze(player_type *player_ptr, object_type *o_ptr, obj_desc_list *desc_ptr)
1302 {
1303         analyze_general(player_ptr, o_ptr, desc_ptr->description);
1304         analyze_pval(o_ptr, &desc_ptr->pval_info);
1305         analyze_brand(o_ptr, desc_ptr->brands);
1306         analyze_slay(o_ptr, desc_ptr->slays);
1307         analyze_immune(o_ptr, desc_ptr->immunities);
1308         analyze_resist(o_ptr, desc_ptr->resistances);
1309         analyze_sustains(o_ptr, desc_ptr->sustains);
1310         analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
1311         analyze_addition(o_ptr, desc_ptr->addition);
1312         analyze_misc(o_ptr, desc_ptr->misc_desc);
1313         desc_ptr->activation = item_activation(o_ptr);
1314 }
1315
1316
1317 /*!
1318  * @brief バッファにアーティファクト出力情報ヘッダを収める /
1319  * @return なし
1320  */
1321 static void print_header(void)
1322 {
1323         char buf[80];
1324
1325         sprintf(buf, "Artifact Spoilers for Hengband Version %d.%d.%d", FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
1326         spoiler_underline(buf);
1327 }
1328
1329 /*
1330  * This is somewhat ugly.
1331  *
1332  * Given a header ("Resist", e.g.), a list ("Fire", "Cold", Acid", e.g.),
1333  * and a separator character (',', e.g.), write the list to the spoiler file
1334  * in a "nice" format, such as:
1335  *
1336  *      Resist Fire, Cold, Acid
1337  *
1338  * That was a simple example, but when the list is long, a line wrap
1339  * should occur, and this should induce a new level of indention if
1340  * a list is being spread across lines. So for example, Bladeturner's
1341  * list of resistances should look something like this
1342  *
1343  *     Resist Acid, Lightning, Fire, Cold, Poison, Light, Dark, Blindness,
1344  *       Confusion, Sound, Shards, Nether, Nexus, Chaos, Disenchantment
1345  *
1346  * However, the code distinguishes between a single list of many items vs.
1347  * many lists. (The separator is used to make this determination.) A single
1348  * list of many items will not cause line wrapping (since there is no
1349  * apparent reason to do so). So the lists of Ulmo's miscellaneous traits
1350  * might look like this:
1351  *
1352  *     Free Action; Hold Life; See Invisible; Slow Digestion; Regeneration
1353  *     Blessed Blade
1354  *
1355  * So comparing the two, "Regeneration" has no trailing separator and
1356  * "Blessed Blade" was not indented. (Also, Ulmo's lists have no headers,
1357  * but that's not relevant to line wrapping and indention.)
1358  */
1359
1360  /* ITEM_SEP separates items within a list */
1361 #define ITEM_SEP ','
1362
1363
1364 /* LIST_SEP separates lists */
1365 #ifdef JP
1366 #define LIST_SEP ','
1367 #else
1368 #define LIST_SEP ';'
1369 #endif
1370
1371 /*!
1372  * @brief フラグ名称を出力する汎用関数
1373  * @param header ヘッダに出力するフラグ群の名前
1374  * @param list フラグ名リスト
1375  * @param separator フラグ表示の区切り記号
1376  * @return なし
1377  */
1378 static void spoiler_outlist(concptr header, concptr *list, char separator)
1379 {
1380         int line_len, buf_len;
1381         char line[MAX_LINE_LEN + 1], buf[80];
1382
1383         /* Ignore an empty list */
1384         if (*list == NULL) return;
1385
1386         /* This function always indents */
1387         strcpy(line, INDENT1);
1388
1389         /* Create header (if one was given) */
1390         if (header && (header[0]))
1391         {
1392                 strcat(line, header);
1393                 strcat(line, " ");
1394         }
1395
1396         line_len = strlen(line);
1397
1398         /* Now begin the tedious task */
1399         while (TRUE)
1400         {
1401                 /* Copy the current item to a buffer */
1402                 strcpy(buf, *list);
1403
1404                 /* Note the buffer's length */
1405                 buf_len = strlen(buf);
1406
1407                 /*
1408                  * If there is an item following this one, pad with separator and
1409                  * a space and adjust the buffer length
1410                  */
1411
1412                 if (list[1])
1413                 {
1414                         sprintf(buf + buf_len, "%c ", separator);
1415                         buf_len += 2;
1416                 }
1417
1418                 /*
1419                  * If the buffer will fit on the current line, just append the
1420                  * buffer to the line and adjust the line length accordingly.
1421                  */
1422
1423                 if (line_len + buf_len <= MAX_LINE_LEN)
1424                 {
1425                         strcat(line, buf);
1426                         line_len += buf_len;
1427                 }
1428
1429                 /* Apply line wrapping and indention semantics described above */
1430                 else
1431                 {
1432                         /*
1433                          * Don't print a trailing list separator but do print a trailing
1434                          * item separator.
1435                          */
1436                         if (line_len > 1 && line[line_len - 1] == ' '
1437                                 && line[line_len - 2] == LIST_SEP)
1438                         {
1439                                 /* Ignore space and separator */
1440                                 line[line_len - 2] = '\0';
1441
1442                                 /* Write to spoiler file */
1443                                 fprintf(fff, "%s\n", line);
1444
1445                                 /* Begin new line at primary indention level */
1446                                 sprintf(line, "%s%s", INDENT1, buf);
1447                         }
1448
1449                         else
1450                         {
1451                                 /* Write to spoiler file */
1452                                 fprintf(fff, "%s\n", line);
1453
1454                                 /* Begin new line at secondary indention level */
1455                                 sprintf(line, "%s%s", INDENT2, buf);
1456                         }
1457
1458                         line_len = strlen(line);
1459                 }
1460
1461                 /* Advance, with break */
1462                 if (!*++list) break;
1463         }
1464
1465         /* Write what's left to the spoiler file */
1466         fprintf(fff, "%s\n", line);
1467 }
1468
1469 /*!
1470  * @brief アーティファクト一件をスポイラー出力する /
1471  * Create a spoiler file entry for an artifact
1472  * @param art_ptr アーティファクト情報をまとめた構造体の参照ポインタ
1473  * @return なし
1474  */
1475 static void spoiler_print_art(obj_desc_list *art_ptr)
1476 {
1477         pval_info_type *pval_ptr = &art_ptr->pval_info;
1478         char buf[80];
1479
1480         /* Don't indent the first line */
1481         fprintf(fff, "%s\n", art_ptr->description);
1482
1483         /* An "empty" pval description indicates that the pval affects nothing */
1484         if (pval_ptr->pval_desc[0])
1485         {
1486                 /* Mention the effects of pval */
1487                 sprintf(buf, _("%sの修正:", "%s to"), pval_ptr->pval_desc);
1488                 spoiler_outlist(buf, pval_ptr->pval_affects, ITEM_SEP);
1489         }
1490
1491         /* Now deal with the description lists */
1492         spoiler_outlist(_("対:", "Slay"), art_ptr->slays, ITEM_SEP);
1493         spoiler_outlist(_("武器属性:", ""), art_ptr->brands, LIST_SEP);
1494         spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, ITEM_SEP);
1495         spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, ITEM_SEP);
1496         spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustains, ITEM_SEP);
1497         spoiler_outlist("", art_ptr->misc_magic, LIST_SEP);
1498
1499         if (art_ptr->addition[0])
1500         {
1501                 fprintf(fff, _("%s追加: %s\n", "%sAdditional %s\n"), INDENT1, art_ptr->addition);
1502         }
1503
1504         /* Write out the possible activation at the primary indention level */
1505         if (art_ptr->activation)
1506         {
1507                 fprintf(fff, _("%s発動: %s\n", "%sActivates for %s\n"), INDENT1, art_ptr->activation);
1508         }
1509
1510         /* End with the miscellaneous facts */
1511         fprintf(fff, "%s%s\n\n", INDENT1, art_ptr->misc_desc);
1512 }
1513
1514
1515 /*!
1516  * @brief アーティファクト情報を出力するためにダミー生成を行う /
1517  * Hack -- Create a "forged" artifact
1518  * @param o_ptr 一時生成先を保管するオブジェクト構造体
1519  * @param name1 生成するアーティファクトID
1520  * @return 生成が成功した場合TRUEを返す
1521  */
1522 static bool make_fake_artifact(object_type *o_ptr, IDX name1)
1523 {
1524         OBJECT_IDX i;
1525         artifact_type *a_ptr = &a_info[name1];
1526
1527         /* Ignore "empty" artifacts */
1528         if (!a_ptr->name) return FALSE;
1529
1530         /* Acquire the "kind" index */
1531         i = lookup_kind(a_ptr->tval, a_ptr->sval);
1532
1533         if (!i) return FALSE;
1534
1535         object_prep(o_ptr, i);
1536
1537         /* Save the name */
1538         o_ptr->name1 = (byte)name1;
1539
1540         /* Extract the fields */
1541         o_ptr->pval = a_ptr->pval;
1542         o_ptr->ac = a_ptr->ac;
1543         o_ptr->dd = a_ptr->dd;
1544         o_ptr->ds = a_ptr->ds;
1545         o_ptr->to_a = a_ptr->to_a;
1546         o_ptr->to_h = a_ptr->to_h;
1547         o_ptr->to_d = a_ptr->to_d;
1548         o_ptr->weight = a_ptr->weight;
1549
1550         /* Success */
1551         return TRUE;
1552 }
1553
1554
1555 /*!
1556  * @brief アーティファクト情報のスポイラー出力を行うメインルーチン /
1557  * Create a spoiler file for artifacts
1558  * @param player_ptr プレーヤーへの参照ポインタ
1559  * @param fname 生成ファイル名
1560  * @return なし
1561  */
1562 static void spoil_artifact(player_type *player_ptr, concptr fname)
1563 {
1564         int i;
1565         IDX j;
1566
1567         object_type forge;
1568         object_type *q_ptr;
1569         obj_desc_list artifact;
1570         char buf[1024];
1571         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
1572
1573         /* File type is "TEXT" */
1574         FILE_TYPE(FILE_TYPE_TEXT);
1575         fff = my_fopen(buf, "w");
1576
1577         if (!fff)
1578         {
1579                 msg_print("Cannot create spoiler file.");
1580                 return;
1581         }
1582
1583         /* Dump the header */
1584         print_header();
1585
1586         /* List the artifacts by tval */
1587         for (i = 0; group_artifact[i].tval; i++)
1588         {
1589                 /* Write out the group title */
1590                 if (group_artifact[i].name)
1591                 {
1592                         spoiler_blanklines(2);
1593                         spoiler_underline(group_artifact[i].name);
1594                         spoiler_blanklines(1);
1595                 }
1596
1597                 /* Now search through all of the artifacts */
1598                 for (j = 1; j < max_a_idx; ++j)
1599                 {
1600                         artifact_type *a_ptr = &a_info[j];
1601
1602                         /* We only want objects in the current group */
1603                         if (a_ptr->tval != group_artifact[i].tval) continue;
1604                         q_ptr = &forge;
1605                         object_wipe(q_ptr);
1606
1607                         /* Attempt to "forge" the artifact */
1608                         if (!make_fake_artifact(q_ptr, j)) continue;
1609
1610                         /* Analyze the artifact */
1611                         object_analyze(player_ptr, q_ptr, &artifact);
1612
1613                         /* Write out the artifact description to the spoiler file */
1614                         spoiler_print_art(&artifact);
1615                 }
1616         }
1617
1618         /* Check for errors */
1619         if (ferror(fff) || my_fclose(fff))
1620         {
1621                 msg_print("Cannot close spoiler file.");
1622                 return;
1623         }
1624
1625         msg_print("Successfully created a spoiler file.");
1626 }
1627
1628
1629 /*!
1630  * @brief モンスター簡易情報のスポイラー出力を行うメインルーチン /
1631  * Create a spoiler file for monsters   -BEN-
1632  * @param fname 生成ファイル名
1633  * @return なし
1634  */
1635 static void spoil_mon_desc(concptr fname)
1636 {
1637         int i, n = 0;
1638
1639         u16b why = 2;
1640         MONRACE_IDX *who;
1641
1642         char buf[1024];
1643
1644         char nam[80];
1645         char lev[80];
1646         char rar[80];
1647         char spd[80];
1648         char ac[80];
1649         char hp[80];
1650         char exp[80];
1651         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
1652
1653         /* File type is "TEXT" */
1654         FILE_TYPE(FILE_TYPE_TEXT);
1655         fff = my_fopen(buf, "w");
1656
1657         if (!fff)
1658         {
1659                 msg_print("Cannot create spoiler file.");
1660                 return;
1661         }
1662
1663         /* Allocate the "who" array */
1664         C_MAKE(who, max_r_idx, MONRACE_IDX);
1665
1666         /* Dump the header */
1667         fprintf(fff, "Monster Spoilers for Hengband Version %d.%d.%d\n",
1668                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
1669         fprintf(fff, "------------------------------------------\n\n");
1670
1671         /* Dump the header */
1672         fprintf(fff, "    %-38.38s%4s%4s%4s%7s%5s  %11.11s\n",
1673                 "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
1674         fprintf(fff, "%-42.42s%4s%4s%4s%7s%5s  %11.11s\n",
1675                 "--------", "---", "---", "---", "--", "--", "-----------");
1676
1677
1678         /* Scan the monsters */
1679         for (i = 1; i < max_r_idx; i++)
1680         {
1681                 monster_race *r_ptr = &r_info[i];
1682
1683                 /* Use that monster */
1684                 if (r_ptr->name) who[n++] = (s16b)i;
1685         }
1686
1687         /* Sort the array by dungeon depth of monsters */
1688         ang_sort(who, &why, n, ang_sort_comp_hook, ang_sort_swap_hook);
1689
1690         /* Scan again */
1691         for (i = 0; i < n; i++)
1692         {
1693                 monster_race *r_ptr = &r_info[who[i]];
1694
1695                 concptr name = (r_name + r_ptr->name);
1696                 if (r_ptr->flags7 & (RF7_KAGE)) continue;
1697
1698                 /* Get the "name" */
1699                 /*
1700                 else if (r_ptr->flags3 & (RF3_NO_CONF))
1701                 {
1702                         sprintf(nam, "[*] %s", name);
1703                 }
1704                 */
1705                 else if (r_ptr->flags1 & (RF1_UNIQUE))
1706                 {
1707                         sprintf(nam, "[U] %s", name);
1708                 }
1709                 else
1710                 {
1711                         sprintf(nam, _("    %s", "The %s"), name);
1712                 }
1713
1714                 /* Level */
1715                 sprintf(lev, "%d", (int)r_ptr->level);
1716
1717                 /* Rarity */
1718                 sprintf(rar, "%d", (int)r_ptr->rarity);
1719
1720                 if (r_ptr->speed >= 110)
1721                 {
1722                         sprintf(spd, "+%d", (r_ptr->speed - 110));
1723                 }
1724                 else
1725                 {
1726                         sprintf(spd, "-%d", (110 - r_ptr->speed));
1727                 }
1728
1729                 /* Armor Class */
1730                 sprintf(ac, "%d", r_ptr->ac);
1731
1732                 /* Hitpoints */
1733                 if ((r_ptr->flags1 & (RF1_FORCE_MAXHP)) || (r_ptr->hside == 1))
1734                 {
1735                         sprintf(hp, "%d", r_ptr->hdice * r_ptr->hside);
1736                 }
1737                 else
1738                 {
1739                         sprintf(hp, "%dd%d", r_ptr->hdice, r_ptr->hside);
1740                 }
1741
1742
1743                 /* Experience */
1744                 sprintf(exp, "%ld", (long)(r_ptr->mexp));
1745
1746                 /* Hack -- use visual instead */
1747                 sprintf(exp, "%s '%c'", attr_to_text(r_ptr), r_ptr->d_char);
1748
1749                 /* Dump the info */
1750                 fprintf(fff, "%-42.42s%4s%4s%4s%7s%5s  %11.11s\n",
1751                         nam, lev, rar, spd, hp, ac, exp);
1752         }
1753
1754         /* End it */
1755         fprintf(fff, "\n");
1756
1757
1758         /* Free the "who" array */
1759         C_KILL(who, max_r_idx, s16b);
1760
1761         /* Check for errors */
1762         if (ferror(fff) || my_fclose(fff))
1763         {
1764                 msg_print("Cannot close spoiler file.");
1765                 return;
1766         }
1767
1768         /* Worked */
1769         msg_print("Successfully created a spoiler file.");
1770 }
1771
1772
1773
1774
1775 /*
1776  * Monster spoilers by: smchorse@ringer.cs.utsa.edu (Shawn McHorse)
1777  *
1778  * Primarily based on code already in mon-desc.c, mostly by -BEN-
1779  */
1780
1781
1782
1783  /*!
1784   * @brief 文字列をファイルポインタに出力する /
1785   * Buffer text to the given file. (-SHAWN-)
1786   * This is basically c_roff() from mon-desc.c with a few changes.
1787   * @param str 文字列参照ポインタ
1788   * @return なし
1789   */
1790 static void spoil_out(concptr str)
1791 {
1792         concptr r;
1793
1794         /* Line buffer */
1795         static char roff_buf[256];
1796
1797         /* Delay buffer */
1798         static char roff_waiting_buf[256];
1799
1800 #ifdef JP
1801         bool iskanji_flag = FALSE;
1802 #endif
1803         /* Current pointer into line roff_buf */
1804         static char *roff_p = roff_buf;
1805
1806         /* Last space saved into roff_buf */
1807         static char *roff_s = NULL;
1808
1809         /* Mega-Hack -- Delayed output */
1810         static bool waiting_output = FALSE;
1811
1812         /* Special handling for "new sequence" */
1813         if (!str)
1814         {
1815                 if (waiting_output)
1816                 {
1817                         fputs(roff_waiting_buf, fff);
1818                         waiting_output = FALSE;
1819                 }
1820
1821                 if (roff_p != roff_buf) roff_p--;
1822                 while (*roff_p == ' ' && roff_p != roff_buf) roff_p--;
1823
1824                 if (roff_p == roff_buf) fprintf(fff, "\n");
1825                 else
1826                 {
1827                         *(roff_p + 1) = '\0';
1828                         fprintf(fff, "%s\n\n", roff_buf);
1829                 }
1830
1831                 roff_p = roff_buf;
1832                 roff_s = NULL;
1833                 roff_buf[0] = '\0';
1834                 return;
1835         }
1836
1837         /* Scan the given string, character at a time */
1838         for (; *str; str++)
1839         {
1840 #ifdef JP
1841                 char cbak;
1842                 bool k_flag = iskanji((unsigned char)(*str));
1843 #endif
1844                 char ch = *str;
1845                 bool wrap = (ch == '\n');
1846
1847 #ifdef JP
1848                 if (!isprint((unsigned char)ch) && !k_flag && !iskanji_flag) ch = ' ';
1849                 iskanji_flag = k_flag && !iskanji_flag;
1850 #else
1851                 if (!isprint(ch)) ch = ' ';
1852 #endif
1853
1854                 if (waiting_output)
1855                 {
1856                         fputs(roff_waiting_buf, fff);
1857                         if (!wrap) fputc('\n', fff);
1858                         waiting_output = FALSE;
1859                 }
1860
1861                 if (!wrap)
1862                 {
1863 #ifdef JP
1864                         if (roff_p >= roff_buf + (k_flag ? 74 : 75)) wrap = TRUE;
1865                         else if ((ch == ' ') && (roff_p >= roff_buf + (k_flag ? 72 : 73))) wrap = TRUE;
1866 #else
1867                         if (roff_p >= roff_buf + 75) wrap = TRUE;
1868                         else if ((ch == ' ') && (roff_p >= roff_buf + 73)) wrap = TRUE;
1869 #endif
1870
1871                         if (wrap)
1872                         {
1873 #ifdef JP
1874                                 bool k_flag_local;
1875                                 bool iskanji_flag_local = FALSE;
1876                                 concptr tail = str + (k_flag ? 2 : 1);
1877 #else
1878                                 concptr tail = str + 1;
1879 #endif
1880
1881                                 for (; *tail; tail++)
1882                                 {
1883                                         if (*tail == ' ') continue;
1884
1885 #ifdef JP
1886                                         k_flag_local = iskanji((unsigned char)(*tail));
1887                                         if (isprint((unsigned char)*tail) || k_flag_local || iskanji_flag_local) break;
1888                                         iskanji_flag_local = k_flag_local && !iskanji_flag_local;
1889 #else
1890                                         if (isprint(*tail)) break;
1891 #endif
1892                                 }
1893
1894                                 if (!*tail) waiting_output = TRUE;
1895                         }
1896                 }
1897
1898                 /* Handle line-wrap */
1899                 if (wrap)
1900                 {
1901                         *roff_p = '\0';
1902                         r = roff_p;
1903 #ifdef JP
1904                         cbak = ' ';
1905 #endif
1906                         if (roff_s && (ch != ' '))
1907                         {
1908 #ifdef JP
1909                                 cbak = *roff_s;
1910 #endif
1911                                 *roff_s = '\0';
1912                                 r = roff_s + 1;
1913                         }
1914                         if (!waiting_output) fprintf(fff, "%s\n", roff_buf);
1915                         else strcpy(roff_waiting_buf, roff_buf);
1916                         roff_s = NULL;
1917                         roff_p = roff_buf;
1918 #ifdef JP
1919                         if (cbak != ' ') *roff_p++ = cbak;
1920 #endif
1921                         while (*r) *roff_p++ = *r++;
1922                 }
1923
1924                 /* Save the char */
1925                 if ((roff_p > roff_buf) || (ch != ' '))
1926                 {
1927 #ifdef JP
1928                         if (!k_flag)
1929                         {
1930                                 if ((ch == ' ') || (ch == '(')) roff_s = roff_p;
1931                         }
1932                         else
1933                         {
1934                                 if (iskanji_flag &&
1935                                         strncmp(str, "。", 2) != 0 &&
1936                                         strncmp(str, "、", 2) != 0 &&
1937                                         strncmp(str, "ィ", 2) != 0 &&
1938                                         strncmp(str, "ー", 2) != 0) roff_s = roff_p;
1939                         }
1940 #else
1941                         if (ch == ' ') roff_s = roff_p;
1942 #endif
1943
1944                         *roff_p++ = ch;
1945                 }
1946         }
1947 }
1948
1949
1950
1951 /*!
1952  * @brief 関数ポインタ用の出力関数 /
1953  * Hook function used in spoil_mon_info()
1954  * @param attr 未使用
1955  * @param str 文字列参照ポインタ
1956  * @return なし
1957  */
1958 static void roff_func(TERM_COLOR attr, concptr str)
1959 {
1960         /* Unused */
1961         (void)attr;
1962
1963         spoil_out(str);
1964 }
1965
1966
1967 /*!
1968  * @brief モンスター詳細情報をスポイラー出力するメインルーチン /
1969  * Create a spoiler file for monsters (-SHAWN-)
1970  * @param fname ファイル名
1971  * @return なし
1972  */
1973 static void spoil_mon_info(player_type *player_ptr, concptr fname)
1974 {
1975         char buf[1024];
1976         int i, l, n = 0;
1977         BIT_FLAGS flags1;
1978
1979         u16b why = 2;
1980         MONRACE_IDX *who;
1981         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
1982
1983         /* File type is "TEXT" */
1984         FILE_TYPE(FILE_TYPE_TEXT);
1985         fff = my_fopen(buf, "w");
1986
1987         if (!fff)
1988         {
1989                 msg_print("Cannot create spoiler file.");
1990                 return;
1991         }
1992
1993
1994         /* Dump the header */
1995         sprintf(buf, "Monster Spoilers for Hengband Version %d.%d.%d\n",
1996                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
1997
1998         spoil_out(buf);
1999         spoil_out("------------------------------------------\n\n");
2000
2001         /* Allocate the "who" array */
2002         C_MAKE(who, max_r_idx, MONRACE_IDX);
2003
2004         /* Scan the monsters */
2005         for (i = 1; i < max_r_idx; i++)
2006         {
2007                 monster_race *r_ptr = &r_info[i];
2008
2009                 /* Use that monster */
2010                 if (r_ptr->name) who[n++] = (s16b)i;
2011         }
2012
2013         ang_sort(who, &why, n, ang_sort_comp_hook, ang_sort_swap_hook);
2014
2015         /*
2016          * List all monsters in order
2017          */
2018         for (l = 0; l < n; l++)
2019         {
2020                 monster_race *r_ptr = &r_info[who[l]];
2021                 flags1 = r_ptr->flags1;
2022
2023                 /* Prefix */
2024                 /*
2025                 if (flags1 & (RF1_QUESTOR))
2026                 {
2027                         spoil_out("[Q] ");
2028                 }
2029                 else
2030                 */
2031                 if (flags1 & (RF1_UNIQUE))
2032                 {
2033                         spoil_out("[U] ");
2034                 }
2035                 else
2036                 {
2037 #ifdef JP
2038 #else
2039                         spoil_out("The ");
2040 #endif
2041                 }
2042
2043                 /* Name */
2044                 sprintf(buf, _("%s/%s  (", "%s%s ("), (r_name + r_ptr->name), _(r_name + r_ptr->E_name, ""));  /* ---)--- */
2045
2046                 spoil_out(buf);
2047
2048                 /* Color */
2049                 spoil_out(attr_to_text(r_ptr));
2050
2051                 /* Symbol --(-- */
2052                 sprintf(buf, " '%c')\n", r_ptr->d_char);
2053                 spoil_out(buf);
2054
2055
2056                 /* Indent */
2057                 sprintf(buf, "=== ");
2058                 spoil_out(buf);
2059
2060                 /* Number */
2061                 sprintf(buf, "Num:%d  ", who[l]);
2062                 spoil_out(buf);
2063
2064                 /* Level */
2065                 sprintf(buf, "Lev:%d  ", (int)r_ptr->level);
2066                 spoil_out(buf);
2067
2068                 /* Rarity */
2069                 sprintf(buf, "Rar:%d  ", r_ptr->rarity);
2070                 spoil_out(buf);
2071
2072                 if (r_ptr->speed >= 110)
2073                 {
2074                         sprintf(buf, "Spd:+%d  ", (r_ptr->speed - 110));
2075                 }
2076                 else
2077                 {
2078                         sprintf(buf, "Spd:-%d  ", (110 - r_ptr->speed));
2079                 }
2080                 spoil_out(buf);
2081
2082                 /* Hitpoints */
2083                 if ((flags1 & (RF1_FORCE_MAXHP)) || (r_ptr->hside == 1))
2084                 {
2085                         sprintf(buf, "Hp:%d  ", r_ptr->hdice * r_ptr->hside);
2086                 }
2087                 else
2088                 {
2089                         sprintf(buf, "Hp:%dd%d  ", r_ptr->hdice, r_ptr->hside);
2090                 }
2091                 spoil_out(buf);
2092
2093                 /* Armor Class */
2094                 sprintf(buf, "Ac:%d  ", r_ptr->ac);
2095                 spoil_out(buf);
2096
2097                 /* Experience */
2098                 sprintf(buf, "Exp:%ld\n", (long)(r_ptr->mexp));
2099                 spoil_out(buf);
2100
2101                 /* Reuse the code of monster recall. */
2102                 output_monster_spoiler(player_ptr, who[l], roff_func);
2103
2104                 spoil_out(NULL);
2105         }
2106
2107         /* Free the "who" array */
2108         C_KILL(who, max_r_idx, s16b);
2109
2110         /* Check for errors */
2111         if (ferror(fff) || my_fclose(fff))
2112         {
2113                 msg_print("Cannot close spoiler file.");
2114                 return;
2115         }
2116
2117         msg_print("Successfully created a spoiler file.");
2118 }
2119
2120
2121
2122 #define MAX_EVOL_DEPTH 64
2123
2124
2125 /*!
2126  * @brief int配列でstrncmp()と似た比較処理を行う /
2127  * Compare two int-type array like strncmp() and return TRUE if equals
2128  * @param a 比較するint配列1
2129  * @param b 比較するint配列2
2130  * @param length
2131  * @return 両者の値が等しければTRUEを返す
2132  */
2133 static bool int_n_cmp(int *a, int *b, int length)
2134 {
2135         /* Null-string comparation is always TRUE */
2136         if (!length) return TRUE;
2137
2138         do
2139         {
2140                 if (*a != *(b++)) return FALSE;
2141                 if (!(*(a++))) break;
2142         } while (--length);
2143
2144         return TRUE;
2145 }
2146
2147
2148 /*!
2149  * @brief ある木が指定された木の部分木かどうかを返す /
2150  * Returns TRUE if an evolution tree is "partial tree"
2151  * @param tree 元となる木構造リスト
2152  * @param partial_tree 部分木かどうか判定したい木構造リスト
2153  * @return 部分木ならばTRUEを返す
2154  */
2155 static bool is_partial_tree(int *tree, int *partial_tree)
2156 {
2157         int pt_head = *(partial_tree++);
2158         int pt_len = 0;
2159
2160         while (partial_tree[pt_len]) pt_len++;
2161
2162         while (*tree)
2163         {
2164                 if (*(tree++) == pt_head)
2165                 {
2166                         if (int_n_cmp(tree, partial_tree, pt_len)) return TRUE;
2167                 }
2168         }
2169
2170         return FALSE;
2171 }
2172
2173 /*!
2174  * @brief 進化ツリーをスポイラー出力するメインルーチン /
2175  * Print monsters' evolution information to file
2176  * @param fname 出力ファイル名
2177  * @return なし
2178  */
2179 static void spoil_mon_evol(concptr fname)
2180 {
2181         char buf[1024];
2182         monster_race *r_ptr;
2183         int **evol_tree, i, j, n, r_idx;
2184         int *evol_tree_zero; /* For C_KILL() */
2185         path_build(buf, sizeof buf, ANGBAND_DIR_USER, fname);
2186
2187         /* File type is "TEXT" */
2188         FILE_TYPE(FILE_TYPE_TEXT);
2189         fff = my_fopen(buf, "w");
2190
2191         if (!fff)
2192         {
2193                 msg_print("Cannot create spoiler file.");
2194                 return;
2195         }
2196
2197         /* Dump the header */
2198         sprintf(buf, "Monster Spoilers for Hengband Version %d.%d.%d\n",
2199                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
2200
2201         spoil_out(buf);
2202         spoil_out("------------------------------------------\n\n");
2203
2204         /* Allocate the "evol_tree" array (2-dimension) */
2205         C_MAKE(evol_tree, max_r_idx, int *);
2206         C_MAKE(*evol_tree, max_r_idx * (MAX_EVOL_DEPTH + 1), int);
2207         for (i = 1; i < max_r_idx; i++) evol_tree[i] = *evol_tree + i * (MAX_EVOL_DEPTH + 1);
2208         evol_tree_zero = *evol_tree;
2209
2210         /* Step 1: Build the evolution tree */
2211         for (i = 1; i < max_r_idx; i++)
2212         {
2213                 r_ptr = &r_info[i];
2214
2215                 /* No evolution */
2216                 if (!r_ptr->next_exp) continue;
2217
2218                 /* Trace evolution */
2219                 n = 0;
2220                 evol_tree[i][n++] = i;
2221                 do
2222                 {
2223                         evol_tree[i][n++] = r_ptr->next_r_idx;
2224                         r_ptr = &r_info[r_ptr->next_r_idx];
2225                 } while (r_ptr->next_exp && (n < MAX_EVOL_DEPTH));
2226         }
2227
2228         /* Step 2: Scan the evolution trees and remove "partial tree" */
2229         for (i = 1; i < max_r_idx; i++)
2230         {
2231                 /* Not evolution tree */
2232                 if (!evol_tree[i][0]) continue;
2233
2234                 for (j = 1; j < max_r_idx; j++)
2235                 {
2236                         /* Same tree */
2237                         if (i == j) continue;
2238
2239                         /* Not evolution tree */
2240                         if (!evol_tree[j][0]) continue;
2241
2242                         /* Is evolution tree[i] is part of [j]? */
2243                         if (is_partial_tree(evol_tree[j], evol_tree[i]))
2244                         {
2245                                 /* Remove this evolution tree */
2246                                 evol_tree[i][0] = 0;
2247                                 break;
2248                         }
2249                 }
2250         }
2251
2252         /* Step 3: Sort the evolution trees */
2253         ang_sort(evol_tree, NULL, max_r_idx, ang_sort_comp_evol_tree, ang_sort_swap_evol_tree);
2254
2255         /* Step 4: Print the evolution trees */
2256         for (i = 0; i < max_r_idx; i++)
2257         {
2258                 r_idx = evol_tree[i][0];
2259
2260                 /* No evolution or removed evolution tree */
2261                 if (!r_idx) continue;
2262
2263                 /* Trace the evolution tree */
2264                 r_ptr = &r_info[r_idx];
2265                 fprintf(fff, _("[%d]: %s (レベル%d, '%c')\n", "[%d]: %s (Level %d, '%c')\n"),
2266                         r_idx, r_name + r_ptr->name, (int)r_ptr->level, r_ptr->d_char);
2267
2268                 for (n = 1; r_ptr->next_exp; n++)
2269                 {
2270                         fprintf(fff, "%*s-(%ld)-> ", n * 2, "", (long int)r_ptr->next_exp);
2271                         fprintf(fff, "[%d]: ", r_ptr->next_r_idx);
2272                         r_ptr = &r_info[r_ptr->next_r_idx];
2273                         fprintf(fff, _("%s (レベル%d, '%c')\n", "%s (Level %d, '%c')\n"),
2274                                 r_name + r_ptr->name, (int)r_ptr->level, r_ptr->d_char);
2275                 }
2276
2277                 /* End of evolution tree */
2278                 fputc('\n', fff);
2279         }
2280
2281         /* Free the "evol_tree" array (2-dimension) */
2282         C_KILL(evol_tree_zero, max_r_idx * (MAX_EVOL_DEPTH + 1), int);
2283         C_KILL(evol_tree, max_r_idx, int *);
2284
2285         /* Check for errors */
2286         if (ferror(fff) || my_fclose(fff))
2287         {
2288                 msg_print("Cannot close spoiler file.");
2289                 return;
2290         }
2291
2292         msg_print("Successfully created a spoiler file.");
2293 }
2294
2295
2296 /*!
2297  * @brief スポイラー出力を行うコマンドのメインルーチン /
2298  * Create Spoiler files -BEN-
2299  * @return なし
2300  */
2301 void do_cmd_spoilers(player_type *player_ptr)
2302 {
2303         screen_save();
2304
2305         /* Interact */
2306         while (TRUE)
2307         {
2308                 Term_clear();
2309
2310                 /* Info */
2311                 prt("Create a spoiler file.", 2, 0);
2312
2313                 /* Prompt for a file */
2314                 prt("(1) Brief Object Info (obj-desc.txt)", 5, 5);
2315                 prt("(2) Brief Artifact Info (artifact.txt)", 6, 5);
2316                 prt("(3) Brief Monster Info (mon-desc.txt)", 7, 5);
2317                 prt("(4) Full Monster Info (mon-info.txt)", 8, 5);
2318                 prt("(5) Monster Evolution Info (mon-evol.txt)", 9, 5);
2319
2320                 /* Prompt */
2321                 prt(_("コマンド:", "Command: "), _(18, 12), 0);
2322
2323                 /* Get a choice */
2324                 switch (inkey())
2325                 {
2326                         /* Escape */
2327                 case ESCAPE:
2328                         screen_load();
2329                         return;
2330
2331                         /* Option (1) */
2332                 case '1':
2333                         spoil_obj_desc(player_ptr, "obj-desc.txt");
2334                         break;
2335
2336                         /* Option (2) */
2337                 case '2':
2338                         spoil_artifact(player_ptr, "artifact.txt");
2339                         break;
2340
2341                         /* Option (3) */
2342                 case '3':
2343                         spoil_mon_desc("mon-desc.txt");
2344                         break;
2345
2346                         /* Option (4) */
2347                 case '4':
2348                         spoil_mon_info(player_ptr, "mon-info.txt");
2349                         break;
2350
2351                         /* Option (5) */
2352                 case '5':
2353                         spoil_mon_evol("mon-evol.txt");
2354                         break;
2355
2356                 default:
2357                         bell();
2358                         break;
2359                 }
2360
2361                 msg_erase();
2362         }
2363 }
2364
2365 /*!
2366  * @brief ランダムアーティファクト1件を解析する /
2367  * Fill in an object description structure for a given object
2368  * @param player_ptr プレーヤーへの参照ポインタ
2369  * @param o_ptr ランダムアーティファクトのオブジェクト構造体参照ポインタ
2370  * @param desc_ptr 記述内容を収める構造体参照ポインタ
2371  * @return なし
2372  */
2373 static void random_artifact_analyze(player_type *player_ptr, object_type *o_ptr, obj_desc_list *desc_ptr)
2374 {
2375         analyze_general(player_ptr, o_ptr, desc_ptr->description);
2376         analyze_pval(o_ptr, &desc_ptr->pval_info);
2377         analyze_brand(o_ptr, desc_ptr->brands);
2378         analyze_slay(o_ptr, desc_ptr->slays);
2379         analyze_immune(o_ptr, desc_ptr->immunities);
2380         analyze_resist(o_ptr, desc_ptr->resistances);
2381         analyze_sustains(o_ptr, desc_ptr->sustains);
2382         analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
2383         desc_ptr->activation = item_activation(o_ptr);
2384 #ifdef JP
2385         sprintf(desc_ptr->misc_desc, "重さ %d.%d kg",
2386                 lbtokg1(o_ptr->weight), lbtokg2(o_ptr->weight));
2387 #else
2388         sprintf(desc_ptr->misc_desc, "Weight %d.%d lbs",
2389                 o_ptr->weight / 10, o_ptr->weight % 10);
2390 #endif
2391 }
2392
2393 /*!
2394  * @brief ランダムアーティファクト1件をスポイラー出力する /
2395  * Create a spoiler file entry for an artifact
2396  * @param o_ptr ランダムアーティファクトのオブジェクト構造体参照ポインタ
2397  * @param art_ptr 記述内容を収めた構造体参照ポインタ
2398  * Fill in an object description structure for a given object
2399  * @return なし
2400  */
2401 static void spoiler_print_randart(object_type *o_ptr, obj_desc_list *art_ptr)
2402 {
2403         pval_info_type *pval_ptr = &art_ptr->pval_info;
2404
2405         char buf[80];
2406
2407         /* Don't indent the first line */
2408         fprintf(fff, "%s\n", art_ptr->description);
2409
2410         /* unidentified */
2411         if (!OBJECT_IS_FULL_KNOWN(o_ptr))
2412         {
2413                 fprintf(fff, _("%s不明\n", "%sUnknown\n"), INDENT1);
2414         }
2415         else {
2416                 /* An "empty" pval description indicates that the pval affects nothing */
2417                 if (pval_ptr->pval_desc[0])
2418                 {
2419                         /* Mention the effects of pval */
2420                         sprintf(buf, _("%sの修正:", "%s to"), pval_ptr->pval_desc);
2421                         spoiler_outlist(buf, pval_ptr->pval_affects, ITEM_SEP);
2422                 }
2423
2424                 /* Now deal with the description lists */
2425
2426                 spoiler_outlist(_("対:", "Slay"), art_ptr->slays, ITEM_SEP);
2427                 spoiler_outlist(_("武器属性:", ""), art_ptr->brands, LIST_SEP);
2428                 spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, ITEM_SEP);
2429                 spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, ITEM_SEP);
2430                 spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustains, ITEM_SEP);
2431                 spoiler_outlist("", art_ptr->misc_magic, LIST_SEP);
2432
2433                 /* Write out the possible activation at the primary indention level */
2434                 if (art_ptr->activation)
2435                 {
2436                         fprintf(fff, _("%s発動: %s\n", "%sActivates for %s\n"), INDENT1, art_ptr->activation);
2437                 }
2438         }
2439         /* End with the miscellaneous facts */
2440         fprintf(fff, "%s%s\n\n", INDENT1, art_ptr->misc_desc);
2441 }
2442
2443
2444 /*!
2445  * @brief ランダムアーティファクト内容をスポイラー出力するサブルーチン /
2446  * @param player_ptr プレーヤーへの参照ポインタ
2447  * @param o_ptr ランダムアーティファクトのオブジェクト構造体参照ポインタ
2448  * @param i 出力したい記録ランダムアーティファクトID
2449  * @return なし
2450  */
2451 static void spoil_random_artifact_aux(player_type *player_ptr, object_type *o_ptr, int i)
2452 {
2453         obj_desc_list artifact;
2454
2455         if (!object_is_known(o_ptr) || !o_ptr->art_name
2456                 || o_ptr->tval != group_artifact[i].tval)
2457                 return;
2458
2459         /* Analyze the artifact */
2460         random_artifact_analyze(player_ptr, o_ptr, &artifact);
2461
2462         /* Write out the artifact description to the spoiler file */
2463         spoiler_print_randart(o_ptr, &artifact);
2464 }
2465
2466 /*!
2467  * @brief ランダムアーティファクト内容をスポイラー出力するメインルーチン /
2468  * Create a list file for random artifacts
2469  * @param fname 出力ファイル名
2470  * @return なし
2471  */
2472 void spoil_random_artifact(player_type *creature_ptr, concptr fname)
2473 {
2474         int i, j;
2475
2476         store_type  *store_ptr;
2477         object_type *q_ptr;
2478
2479         char buf[1024];
2480         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
2481
2482         /* File type is "TEXT" */
2483         FILE_TYPE(FILE_TYPE_TEXT);
2484         fff = my_fopen(buf, "w");
2485
2486         if (!fff)
2487         {
2488                 msg_print("Cannot create list file.");
2489                 return;
2490         }
2491
2492         /* Dump the header */
2493         sprintf(buf, "Random artifacts list.\r");
2494         spoiler_underline(buf);
2495
2496         /* List the artifacts by tval */
2497         for (j = 0; group_artifact[j].tval; j++)
2498         {
2499                 /* random artifacts wielding */
2500                 for (i = INVEN_RARM; i < INVEN_TOTAL; i++)
2501                 {
2502                         q_ptr = &creature_ptr->inventory_list[i];
2503                         spoil_random_artifact_aux(creature_ptr, q_ptr, j);
2504                 }
2505
2506                 for (i = 0; i < INVEN_PACK; i++)
2507                 {
2508                         q_ptr = &creature_ptr->inventory_list[i];
2509                         spoil_random_artifact_aux(creature_ptr, q_ptr, j);
2510                 }
2511
2512                 /* random artifacts in home */
2513                 store_ptr = &town_info[1].store[STORE_HOME];
2514                 for (i = 0; i < store_ptr->stock_num; i++)
2515                 {
2516                         q_ptr = &store_ptr->stock[i];
2517                         spoil_random_artifact_aux(creature_ptr, q_ptr, j);
2518                 }
2519
2520                 /* random artifacts in museum */
2521                 store_ptr = &town_info[1].store[STORE_MUSEUM];
2522                 for (i = 0; i < store_ptr->stock_num; i++)
2523                 {
2524                         q_ptr = &store_ptr->stock[i];
2525                         spoil_random_artifact_aux(creature_ptr, q_ptr, j);
2526                 }
2527         }
2528
2529         /* Check for errors */
2530         if (ferror(fff) || my_fclose(fff))
2531         {
2532                 msg_print("Cannot close list file.");
2533                 return;
2534         }
2535
2536         msg_print("Successfully created a list file.");
2537 }